*.ao
*.ao.*
*.so
+*.so.*
*.i486
*.i386
*.bin
*.dsm
*.dmp
-Map.txt
-map.txt
+*.txt
INPUT = include/apidoc_mainpage.h \
include/binary.h \
+ include/modules.h \
include/vfs.h include/vfs_ext.h \
include/fs_devfs.h \
- include/iocache.h include/
+ include/iocache.h \
+ include/apidoc/arch_x86.h \
+ include/tpl_drv_common.h \
+ include/tpl_drv_video.h
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
endif
OBJ = $(addprefix arch/$(ARCHDIR)/,$(A_OBJ))
-OBJ += heap.o messages.o debug.o modules.o lib.o syscalls.o system.o threads.o drvutil.o
+OBJ += heap.o messages.o debug.o modules.o lib.o syscalls.o system.o threads.o drvutil.o logging.o
+OBJ += $(addprefix vfs/fs/, $(addsuffix .o,$(FILESYSTEMS)))
+OBJ += drv/vterm.o drv/proc.o drv/fifo.o drv/iocache.o drv/dma.o drv/pci.o drv/kb.o drv/vga.o
OBJ += binary.o bin/elf.o bin/pe.o
OBJ += vfs/main.o vfs/open.o vfs/acls.o vfs/dir.o vfs/io.o vfs/mount.o vfs/memfile.o vfs/nodecache.o
OBJ += vfs/fs/root.o vfs/fs/devfs.o
-OBJ += $(addprefix vfs/fs/, $(addsuffix .o,$(FILESYSTEMS)))
-OBJ += drv/proc.o drv/fifo.o drv/dma.o drv/iocache.o drv/pci.o drv/kb.o drv/vga.o drv/vterm.o
OBJ += $(addprefix drv/, $(addsuffix .o,$(DRIVERS)))
OBJ := $(addsuffix .$(ARCH), $(OBJ))
MODS += $(addprefix ../Modules/, $(addsuffix .xo.$(ARCH),$(MODULES)))
-BUILD_NUM = 1513
+BUILD_NUM = 1822
A_OBJ = start.ao main.o lib.o desctab.ao errors.o irq.o
A_OBJ += mm_phys.o mm_virt.o
-A_OBJ += proc.o time.o
+A_OBJ += proc.o time.o vm8086.o
#A_OBJ += gdb_stub.o
dd gGDT
; IDT
ALIGN 8
+[global gIDT]
gIDT:
times 256 dd 0x00080000,0x00000F00
[global gIDTPtr]
%macro DEF_IRQ 1
[global Isr%1]
Isr%1:
- ;cli ; HACK!
push 0
push %1
jmp IRQCommon
push fs
push gs
+ mov ax, 0x10
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+
push esp
call ErrorHandler
add esp, 4
push fs
push gs
+ mov ax, 0x10
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+
push esp
call IRQ_Handler
add esp, 4
push fs
push gs
+ mov ax, 0x10
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+
mov eax, [esp+12*4] ; CPU Number
push eax ; Pus as argument
// === IMPORTS ===
extern void MM_PageFault(Uint Addr, Uint ErrorCode, tRegs *Regs);
+extern void VM8086_GPF(tRegs *Regs);
extern void Threads_Dump();
// === PROTOTYPES ===
void ErrorHandler(tRegs *Regs)
{
Uint cr;
+
+ //if( Regs && !(Regs->int_num == 13 && Regs->eflags & 0x20000) )
+ // __asm__ __volatile__ ("xchg %bx, %bx");
+ //Log_Debug("X86", "Regs = %p", Regs);
+ //Log_Debug("X86", "Error %i at 0x%08x", Regs->int_num, Regs->eip);
+
__asm__ __volatile__ ("cli");
+ // Page Fault
if(Regs->int_num == 14)
{
__asm__ __volatile__ ("mov %%cr2, %0":"=r"(cr));
return ;
}
+ // VM8086 GPF
+ if(Regs->int_num == 13 && Regs->eflags & 0x20000)
+ {
+ VM8086_GPF(Regs);
+ return ;
+ }
+
Warning("CPU Error %i - %s, Code: 0x%x",
Regs->int_num, csaERROR_NAMES[Regs->int_num], Regs->err_code);
Warning(" CS:EIP = 0x%04x:%08x", Regs->cs, Regs->eip);
- Warning(" SS:ESP = 0x%04x:%08x", Regs->ss, Regs->esp);
+ if(Regs->cs == 0x08)
+ Warning(" SS:ESP = 0x0010:%08x", 0x10, (Uint)Regs+sizeof(tRegs));
+ else
+ Warning(" SS:ESP = 0x%04x:%08x", Regs->ss, Regs->esp);
Warning(" EFLAGS = 0x%08x", Regs->eflags);
Warning(" EAX %08x ECX %08x EDX %08x EBX %08x",
Regs->eax, Regs->ecx, Regs->edx, Regs->ebx);
switch( Regs->int_num )
{
- case 6:
+ case 6: // #UD
Warning(" Offending bytes: %02x %02x %02x %02x",
*(Uint8*)Regs->eip+0, *(Uint8*)Regs->eip+1,
*(Uint8*)Regs->eip+2, *(Uint8*)Regs->eip+3);
// === MACROS ===
typedef volatile int tSpinlock;
+#define IS_LOCKED(lockptr) (!!(*(tSpinlock*)lockptr))
#define LOCK(lockptr) do {int v=1;\
while(v)__asm__ __volatile__("lock xchgl %%eax, (%%edi)":"=a"(v):"a"(1),"D"(lockptr));}while(0)
#define RELEASE(lockptr) __asm__ __volatile__("lock andl $0, (%%edi)"::"D"(lockptr));
Uint Resvd4[1]; // SS
} tSyscallRegs;
-typedef struct {
- Uint16 LimitLow;
- Uint16 BaseLow;
- Uint8 BaseMid;
- Uint8 Access;
- struct {
- unsigned LimitHi: 4;
- unsigned Flags: 4;
- } __attribute__ ((packed));
- Uint8 BaseHi;
-} __attribute__ ((packed)) tGDT;
-
typedef struct {
#if USE_PAE
Uint PDPT[4];
--- /dev/null
+/**
+ */
+#ifndef _DESCTAB_H_
+#define _DESCTAB_H_
+
+typedef struct {
+ Uint16 LimitLow;
+ Uint16 BaseLow;
+ Uint8 BaseMid;
+ Uint8 Access;
+ struct {
+ unsigned LimitHi: 4;
+ unsigned Flags: 4;
+ } __attribute__ ((packed));
+ Uint8 BaseHi;
+} __attribute__ ((packed)) tGDT;
+
+typedef struct {
+ Uint16 OffsetLo;
+ Uint16 CS;
+ Uint16 Flags;
+ Uint16 OffsetHi;
+} __attribute__ ((packed)) tIDT;
+
+#endif
--- /dev/null
+/*
+ * Acess 2
+ * By John Hodge (thePowersGang)
+ *
+ * multiboot2.h
+ * - Multiboot 2 Header
+ */
+#ifndef _MULTIBOOT2_H_
+#define _MULTIBOOT2_H_
+
+#define MULTIBOOT2_MAGIC 0x36D76289
+
+typedef struct sMultiboot2Info
+{
+ Uint32 TotalSize;
+ Uint32 Reserved; // SBZ
+} tMultiboot2Info;
+
+#endif
--- /dev/null
+/*
+ * Acess2 VM8086 BIOS Interface
+ * - By John Hodge (thePowersGang)
+ *
+ * vm8086.h
+ * - Core Header
+ */
+#ifndef _VM80806_H_
+#define _VM80806_H_
+
+// === TYPES ===
+/**
+ * \note Semi-opaque - Past \a .IP, the implementation may add any data
+ * it needs to the state.
+ */
+typedef struct sVM8086
+{
+ Uint16 AX, CX, DX, BX;
+ Uint16 BP, SP, SI, DI;
+
+ Uint16 SS, DS, ES;
+
+ Uint16 CS, IP;
+
+ struct sVM8086_InternalData *Internal;
+} tVM8086;
+
+// === FUNCTIONS ===
+/**
+ * \brief Create an instance of the VM8086 Emulator
+ * \note Do not free this pointer with ::free, instead use ::VM8086_Free
+ * \return Pointer to a tVM8086 structure, this structure may be larger than
+ * tVM8086 due to internal data.
+ */
+extern tVM8086 *VM8086_Init(void);
+/**
+ * \brief Free an allocated tVM8086 structure
+ * \param State Emulator state to free
+ */
+extern void VM8086_Free(tVM8086 *State);
+/**
+ * \brief Allocate a piece of memory in the emulated address space and
+ * return a host and emulated pointer to it.
+ * \param State Emulator state
+ * \param Size Size of memory block
+ * \param Segment Pointer to location to store the allocated memory's segment
+ * \param Offset Pointet to location to store the allocated memory's offset
+ * \return Host pointer to the allocated memory
+ */
+extern void *VM8086_Allocate(tVM8086 *State, int Size, Uint16 *Segment, Uint16 *Offset);
+/**
+ * \brief Gets a pointer to a piece of emulated memory
+ * \todo Only 1 machine page is garenteed to be contiguous
+ * \param State Emulator State
+ * \param Segment Source Segment
+ * \param Offset Source Offset
+ * \return Host pointer to the emulated memory
+ */
+extern void *VM8086_GetPointer(tVM8086 *State, Uint16 Segment, Uint16 Ofs);
+/**
+ * \brief Calls a real-mode interrupt described by the current state of the IVT.
+ * \param State Emulator State
+ * \param Interrupt BIOS Interrupt to call
+ */
+extern void VM8086_Int(tVM8086 *State, Uint8 Interrupt);
+
+#endif
for( i = 0; i < MAX_CALLBACKS_PER_IRQ; i++ )
{
if( gIRQ_Handlers[Num][i] == NULL ) {
- Log("IRQ_AddHandler: Added IRQ%i Cb#%i %p", Num, i, Callback);
+ Log_Log("IRQ", "Added IRQ%i Cb#%i %p", Num, i, Callback);
gIRQ_Handlers[Num][i] = Callback;
return 1;
}
}
- Warning("IRQ_AddHandler - No free callbacks on IRQ%i", Num);
+ Log_Warning("IRQ", "No free callbacks on IRQ%i", Num);
return 0;
}
* Linker Script
*/
-lowStart = start - 0xC0000000;
-ENTRY(lowStart)
+//lowStart = start - 0xC0000000;
+ENTRY(start)
OUTPUT_FORMAT(elf32-i386)
SECTIONS {
. = 0x100000;
+ __load_addr = .;
.multiboot : AT(ADDR(.multiboot)) {
*(.multiboot)
}
*(.data)
}
+ __bss_start = .;
.bss : AT(ADDR(.bss) - 0xC0000000) {
_sbss = .;
*(COMMON)
*/
#include <acess.h>
#include <mboot.h>
+#include <multiboot2.h>
#include <init.h>
#include <mm_virt.h>
#include <mp.h>
#define VGA_ERRORS 0
// === IMPORTS ===
-extern void Heap_Install();
-extern void Desctab_Install();
-extern void MM_PreinitVirtual();
+extern void Heap_Install(void);
+extern void Desctab_Install(void);
+extern void MM_PreinitVirtual(void);
extern void MM_Install(tMBoot_Info *MBoot);
-extern void MM_InstallVirtual();
-extern void Threads_Init();
-extern int Time_Setup();
+extern void MM_InstallVirtual(void);
+extern void Threads_Init(void);
+extern int Time_Setup(void);
extern Uint Proc_Clone(Uint *Err, Uint Flags);
-extern void Threads_Sleep();
-extern void Threads_Exit();
+extern void Threads_Sleep(void);
+extern void Threads_Exit(void);
+
+extern int Modules_LoadBuiltins(void);
// === GLOBALS ===
+char *gsBootCmdLine = NULL;
// === CODE ===
-int kmain(Uint MbMagic, tMBoot_Info *MbInfo)
+int kmain(Uint MbMagic, void *MbInfoPtr)
{
int i;
tMBoot_Module *mods;
+ tMBoot_Info *mbInfo;
- // Adjust Multiboot structure address
- MbInfo = (void*)( (Uint)MbInfo + KERNEL_BASE );
+ Log("MbMagic = %08x", MbMagic);
+ Log("MbInfoPtr = %p", MbInfoPtr);
+ // Set up non-boot info dependent stuff
Desctab_Install(); // Set up GDT and IDT
MM_PreinitVirtual(); // Initialise vital mappings
- MM_Install( MbInfo ); // Set up physical memory manager
+
+ switch(MbMagic)
+ {
+ // Multiboot 1
+ case MULTIBOOT_MAGIC:
+ // Adjust Multiboot structure address
+ mbInfo = (void*)( (Uint)MbInfoPtr + KERNEL_BASE );
+ gsBootCmdLine = (char*)(mbInfo->CommandLine + KERNEL_BASE);
+
+ MM_Install( mbInfo ); // Set up physical memory manager
+ break;
+
+ // Multiboot 2
+ case MULTIBOOT2_MAGIC:
+ Warning("Multiboot 2 Not yet supported");
+ //MM_InstallMBoot2( MbInfo ); // Set up physical memory manager
+ return 0;
+ break;
+
+ default:
+ Panic("Multiboot magic invalid %08x, expected %08x or %08x\n",
+ MbMagic, MULTIBOOT_MAGIC, MULTIBOOT2_MAGIC);
+ return 0;
+ }
+
MM_InstallVirtual(); // Clean up virtual address space
Heap_Install(); // Create initial heap
- Log("Starting Multitasking...");
+ //Log_Log("Arch", "Starting Multitasking...");
// Start Multitasking
Threads_Init();
// Start Timers
Time_Setup();
- Log("Starting VFS...");
+ Log_Log("Arch", "Starting VFS...");
// Load Virtual Filesystem
VFS_Init();
- Log("Loading Modules...");
+ // Initialise builtin modules
+ Log_Log("Arch", "Initialising builtin modules...");
+ Modules_LoadBuiltins();
+
+ Log_Log("Arch", "Loading %i Modules...", mbInfo->ModuleCount);
// Load initial modules
- mods = (void*)( MbInfo->Modules + KERNEL_BASE );
- for(i=0;i<MbInfo->ModuleCount;i++)
+ mods = (void*)( mbInfo->Modules + KERNEL_BASE );
+ for( i = 0; i < mbInfo->ModuleCount; i ++ )
{
// Adjust into higher half
mods[i].Start += KERNEL_BASE;
mods[i].End += KERNEL_BASE;
mods[i].String += KERNEL_BASE;
- Log("Loading '%s'", mods[i].String);
+ Log_Log("Arch", "Loading '%s'", mods[i].String);
if( !Module_LoadMem( (void *)mods[i].Start, mods[i].End-mods[i].Start, (char *)mods[i].String ) )
{
- Warning("Unable to load module\n");
+ Log_Warning("Arch", "Unable to load module\n");
}
}
// Pass on to Independent Loader
- Log("Loading Configuration...");
- System_Init( (char*)(MbInfo->CommandLine + KERNEL_BASE) );
+ Log_Log("Arch", "Starting system");
+ System_Init( gsBootCmdLine );
// Sleep forever (sleeping beauty)
- for(;;) Threads_Sleep();
+ for(;;)
+ Threads_Sleep();
return 0;
}
tMBoot_MMapEnt *ent;
// --- Find largest address
+ Log("MBoot->MMapAddr = %08x", MBoot->MMapAddr);
MBoot->MMapAddr |= KERNEL_BASE;
ent = (void *)( MBoot->MMapAddr );
while( (Uint)ent < MBoot->MMapAddr + MBoot->MMapLength )
{
+ Log(" ent->Size = %08x", ent->Size);
// Adjust for size
ent->Size += 4;
ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size );
}
- // Get used page count
+ // Get used page count (Kernel)
kernelPages = (Uint)&gKernelEnd - KERNEL_BASE - 0x100000;
kernelPages += 0xFFF; // Page Align
kernelPages >>= 12;
// Mark Multiboot's pages as taken
// - Structure
MM_RefPhys( (Uint)MBoot - KERNEL_BASE );
+ Log("MBoot->ModuleCount = %i", MBoot->ModuleCount);
// - Module List
for(i = (MBoot->ModuleCount*sizeof(tMBoot_Module)+0xFFF)>12; i--; )
MM_RefPhys( MBoot->Modules + (i << 12) );
// - Modules
+ Log("MBoot->Modules = %p", MBoot->Modules);
mods = (void*)(MBoot->Modules + KERNEL_BASE);
for(i = 0; i < MBoot->ModuleCount; i++)
{
int i, idx, sidx;
tPAddr ret;
+ ENTER("iPages iMaxBits", Pages, MaxBits);
+
// Sanity Checks
- if(MaxBits < 0) return 0;
+ if(MaxBits < 0) {
+ LEAVE('i', 0);
+ return 0;
+ }
if(MaxBits > PHYS_BITS) MaxBits = PHYS_BITS;
// Lock
b = idx % 32;
a = idx / 32;
+ #if 0
+ LOG("a=%i, b=%i, idx=%i, sidx=%i", a, b, idx, sidx);
+
// Find free page
- for( ; gaSuperBitmap[a] == -1 && a --; );
+ for( ; gaSuperBitmap[a] == -1 && a --; ) b = 31;
if(a < 0) {
RELEASE( &giPhysAlloc );
Warning("MM_AllocPhysRange - OUT OF MEMORY (Called by %p)", __builtin_return_address(0));
+ LEAVE('i', 0);
return 0;
}
- for( ; gaSuperBitmap[a] & (1 << b); b-- );
+ LOG("a = %i", a);
+ for( ; gaSuperBitmap[a] & (1 << b); b-- ) sidx = 31;
+ LOG("b = %i", b);
idx = a * 32 + b;
- for( ; gaPageBitmap[idx] & (1 << sidx); sidx-- );
+ for( ; gaPageBitmap[idx] & (1 << sidx); sidx-- )
+ LOG("gaPageBitmap[%i] = 0x%08x", idx, gaPageBitmap[idx]);
+
+ LOG("idx = %i, sidx = %i", idx, sidx);
+ #else
+
+ #endif
// Check if the gap is large enough
while( idx >= 0 )
if( idx < 0 ) {
RELEASE( &giPhysAlloc );
Warning("MM_AllocPhysRange - OUT OF MEMORY (Called by %p)", __builtin_return_address(0));
+ LEAVE('i', 0);
+ return 0;
}
// Mark pages used
gaPageReferences[idx*32+sidx] = 1;
gaPageBitmap[ idx ] |= 1 << sidx;
sidx ++;
- if(sidx == 32) { sidx = 0; idx ++; }
+ if(sidx == 32) { sidx = 0; idx ++; }
}
// Get address
// Release Spinlock
RELEASE( &giPhysAlloc );
+ LEAVE('X', ret);
return ret;
}
* 0xFE - Unused
* 0xFF - System Calls / Kernel's User Code
*/
-#define DEBUG 1
+#define DEBUG 0
#define SANITY 1
#include <acess.h>
#include <mm_phys.h>
(ErrorCode&1?"bad/locked":"non-present"),
(ErrorCode&16?" (Instruction Fetch)":"")
);
- Warning("User Pagefault: Instruction at %p accessed %p", Regs->eip, Addr);
+ Warning("User Pagefault: Instruction at %04x:%08x accessed %p", Regs->cs, Regs->eip, Addr);
__asm__ __volatile__ ("sti"); // Restart IRQs
Threads_SegFault(Addr);
return ;
}
/**
- * \fn tVAddr MM_MapHWPage(tPAddr PAddr, Uint Number)
+ * \fn tVAddr MM_MapHWPages(tPAddr PAddr, Uint Number)
* \brief Allocates a contigous number of pages
*/
-tVAddr MM_MapHWPage(tPAddr PAddr, Uint Number)
+tVAddr MM_MapHWPages(tPAddr PAddr, Uint Number)
{
int i, j;
{
phys = MM_AllocPhys();
*PhysAddr = phys;
- ret = MM_MapHWPage(phys, 1);
+ ret = MM_MapHWPages(phys, 1);
if(ret == 0) {
MM_DerefPhys(phys);
LEAVE('i', 0);
}
// Allocated successfully, now map
- ret = MM_MapHWPage(phys, Pages);
+ ret = MM_MapHWPages(phys, Pages);
if( ret == 0 ) {
// If it didn't map, free then return 0
for(;Pages--;phys+=0x1000)
}
/**
- * \fn void MM_UnmapHWPage(tVAddr VAddr, Uint Number)
+ * \fn void MM_UnmapHWPages(tVAddr VAddr, Uint Number)
* \brief Unmap a hardware page
*/
-void MM_UnmapHWPage(tVAddr VAddr, Uint Number)
+void MM_UnmapHWPages(tVAddr VAddr, Uint Number)
{
int i, j;
// Sanity Check
EXPORT(MM_GetPhysAddr);
EXPORT(MM_Map);
//EXPORT(MM_Unmap);
-EXPORT(MM_MapHWPage);
+EXPORT(MM_MapHWPages);
EXPORT(MM_AllocDMA);
-EXPORT(MM_UnmapHWPage);
+EXPORT(MM_UnmapHWPages);
*/
#include <acess.h>
#include <proc.h>
+#include <desctab.h>
#include <mm_virt.h>
#include <errno.h>
#if USE_MP
// === CONSTANTS ===
#define SWITCH_MAGIC 0xFFFACE55 // There is no code in this area
+// Base is 1193182
#define TIMER_DIVISOR 11931 //~100Hz
// === IMPORTS ===
extern tGDT gGDT[];
+extern tIDT gIDT[];
extern void APStartup(); // 16-bit AP startup code
extern Uint GetEIP(); // start.asm
extern Uint32 gaInitPageDir[1024]; // start.asm
extern tThread *Threads_GetNextToRun(int CPU);
extern void Threads_Dump();
extern tThread *Threads_CloneTCB(Uint *Err, Uint Flags);
-extern void Isr7();
+extern void Isr8(); // Double Fault
// === PROTOTYPES ===
void ArchThreads_Init();
tThread *Proc_GetCurThread();
void Proc_ChangeStack();
int Proc_Clone(Uint *Err, Uint Flags);
+void Proc_StartProcess(Uint16 SS, Uint Stack, Uint Flags, Uint16 CS, Uint IP);
void Proc_Scheduler();
// === GLOBALS ===
tTSS gDoubleFault_TSS = {
.ESP0 = (Uint)&gaDoubleFaultStack[1023],
.SS0 = 0x10,
- .EIP = (Uint)Isr7
+ .CR3 = (Uint)gaInitPageDir - KERNEL_BASE,
+ .EIP = (Uint)Isr8,
+ .ESP = (Uint)&gaDoubleFaultStack[1023],
+ .CS = 0x08, .SS = 0x10,
+ .DS = 0x10, .ES = 0x10,
+ .FS = 0x10, .GS = 0x10,
};
// === CODE ===
gGDT[5].BaseMid = (Uint)&gDoubleFault_TSS >> 16;
gGDT[5].BaseHi = (Uint)&gDoubleFault_TSS >> 24;
+ Log_Debug("Proc", "gIDT[8] = {OffsetLo:%04x, CS:%04x, Flags:%04x, OffsetHi:%04x}",
+ gIDT[8].OffsetLo, gIDT[8].CS, gIDT[8].Flags, gIDT[8].OffsetHi);
+ gIDT[8].OffsetLo = 0;
+ gIDT[8].CS = 5<<3;
+ gIDT[8].Flags = 0x8500;
+ gIDT[8].OffsetHi = 0;
+ Log_Debug("Proc", "gIDT[8] = {OffsetLo:%04x, CS:%04x, Flags:%04x, OffsetHi:%04x}",
+ gIDT[8].OffsetLo, gIDT[8].CS, gIDT[8].Flags, gIDT[8].OffsetHi);
+
+ //__asm__ __volatile__ ("xchg %bx, %bx");
+
#if USE_MP
// Initialise Normal TSS(s)
for(pos=0;pos<giNumCPUs;pos++)
while(*Bases)
*--stack = *Bases++;
*--stack = 0; // Return Address
- delta = (Uint)stack; // Reuse delta to save SP
- *--stack = ss; //Stack Segment
- *--stack = delta; //Stack Pointer
- *--stack = 0x0202; //EFLAGS (Resvd (0x2) and IF (0x20))
- *--stack = cs; //Code Segment
- *--stack = Entrypoint; //EIP
+ Proc_StartProcess(ss, (Uint)stack, 0x202, cs, Entrypoint);
+}
+
+void Proc_StartProcess(Uint16 SS, Uint Stack, Uint Flags, Uint16 CS, Uint IP)
+{
+ Uint *stack = (void*)Stack;
+ *--stack = SS; //Stack Segment
+ *--stack = Stack; //Stack Pointer
+ *--stack = Flags; //EFLAGS (Resvd (0x2) and IF (0x20))
+ *--stack = CS; //Code Segment
+ *--stack = IP; //EIP
//PUSHAD
*--stack = 0xAAAAAAAA; // eax
*--stack = 0xCCCCCCCC; // ecx
*--stack = 0x51515151; // esi
*--stack = 0xB4B4B4B4; // ebp
//Individual PUSHs
- *--stack = ss; // ds
- *--stack = ss; // es
- *--stack = ss; // fs
- *--stack = ss; // gs
+ *--stack = SS; // ds
+ *--stack = SS; // es
+ *--stack = SS; // fs
+ *--stack = SS; // gs
__asm__ __volatile__ (
"mov %%eax,%%esp;\n\t" // Set stack pointer
\r
KERNEL_BASE equ 0xC0000000\r
\r
+[extern __load_addr]\r
+[extern __bss_start]\r
+[extern gKernelEnd]\r
[section .multiboot]\r
mboot:\r
; Multiboot macros to make a few lines later more readable\r
dd MULTIBOOT_CHECKSUM\r
dd mboot - KERNEL_BASE ;Location of Multiboot Header\r
\r
+; Multiboot 2 Header\r
+mboot2:\r
+ MULTIBOOT2_HEADER_MAGIC equ 0xE85250D6\r
+ MULTIBOOT2_HEADER_ARCH equ 0\r
+ MULTIBOOT2_HEADER_LENGTH equ (mboot2_end-mboot2)\r
+ MULTIBOOT2_CHECKSUM equ -(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT2_HEADER_ARCH + MULTIBOOT2_HEADER_LENGTH)\r
+ \r
+ dd MULTIBOOT2_HEADER_MAGIC\r
+ dd MULTIBOOT2_HEADER_ARCH\r
+ dd MULTIBOOT2_HEADER_LENGTH\r
+ dd MULTIBOOT2_CHECKSUM\r
+ ; MBoot2 Address Header\r
+ dw 2, 0\r
+ dd 8 + 16\r
+ dd mboot2 ; Location of Multiboot Header\r
+ dd __load_addr - KERNEL_BASE ; Kernel Load base\r
+ dd __bss_start - KERNEL_BASE ; Kernel Data End\r
+ dd gKernelEnd - KERNEL_BASE ; Kernel BSS End\r
+ ; MBoot2 Entry Point Tag\r
+ dw 3, 0\r
+ dd 8 + 4\r
+ dd start - KERNEL_BASE\r
+ ; MBoot2 Module Alignment Tag\r
+ dw 6, 0\r
+ dd 12 ; ???\r
+ dd 0 ; Search me, seems it wants padding\r
+ ; Terminator\r
+ dw 0, 0\r
+ dd 8\r
+mboot2_end:\r
+ \r
[section .text]\r
[extern kmain]\r
[global start]\r
mov eax, [esp]\r
ret\r
\r
+; int CallWithArgArray(void *Ptr, int NArgs, Uint *Args)\r
+; Call a function passing the array as arguments\r
+[global CallWithArgArray]\r
+CallWithArgArray:\r
+ push ebp\r
+ mov ebp, esp\r
+ mov ecx, [ebp+12] ; Get NArgs\r
+ mov edx, [ebp+16]\r
+\r
+.top:\r
+ mov eax, [edx+ecx*4-4]\r
+ push eax\r
+ loop .top\r
+ \r
+ mov eax, [ebp+8]\r
+ call eax\r
+ lea esp, [ebp]\r
+ pop ebp\r
+ ret\r
+\r
[extern Proc_Clone]\r
[extern Threads_Exit]\r
[global SpawnTask]\r
--- /dev/null
+/*
+ * Acess2 VM8086 Driver
+ * - By John Hodge (thePowersGang)
+ */
+#include <acess.h>
+#include <vm8086.h>
+#include <modules.h>
+
+// === CONSTANTS ===
+#define VM8086_MAGIC_CS 0xFFFF
+#define VM8086_MAGIC_IP 0x0010
+#define VM8086_STACK_SEG 0x9F00
+#define VM8086_STACK_OFS 0x0AFE
+enum eVM8086_Opcodes
+{
+ VM8086_OP_PUSHF = 0x9C,
+ VM8086_OP_POPF = 0x9D,
+ VM8086_OP_INT_I = 0xCD,
+ VM8086_OP_IRET = 0xCF,
+ VM8086_OP_IN_AD = 0xEC,
+ VM8086_OP_IN_ADX= 0xED
+};
+#define VM8086_PAGES_PER_INST 4
+
+// === IMPORTS ===
+ int Proc_Clone(Uint *Err, Uint Flags);
+
+// === TYPES ===
+struct sVM8086_InternalData
+{
+ struct {
+ Uint32 Bitmap; // 32 sections = 128 byte blocks
+ tVAddr VirtBase;
+ tPAddr PhysAddr;
+ } AllocatedPages[VM8086_PAGES_PER_INST];
+};
+
+// === PROTOTYPES ===
+ int VM8086_Install(char **Arguments);
+void VM8086_GPF(tRegs *Regs);
+tVM8086 *VM8086_Init(void);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, 0x100, VM8086, VM8086_Install, NULL, NULL);
+tSpinlock glVM8086_Process;
+tPID gVM8086_WorkerPID;
+tTID gVM8086_CallingThread;
+tVM8086 * volatile gpVM8086_State;
+
+// === FUNCTIONS ===
+int VM8086_Install(char **Arguments)
+{
+ tPID pid;
+
+ // Create BIOS Call process
+ pid = Proc_Clone(NULL, CLONE_VM);
+ if(pid == -1)
+ {
+ Log_Error("VM8086", "Unable to clone kernel into VM8086 worker");
+ return MODULE_ERR_MISC;
+ }
+ if(pid == 0)
+ {
+ Uint *stacksetup; // Initialising Stack
+ Uint16 *rmstack; // Real Mode Stack
+ int i;
+
+ // Set Image Name
+ Threads_SetName("VM8086");
+
+ // Map ROM Area
+ for(i=0xA0;i<0x100;i++) {
+ MM_Map( i * 0x1000, i * 0x1000 );
+ //MM_SetFlags( i * 0x1000, MM_PFLAG_RO, MM_PFLAG_RO ); // Set Read Only
+ }
+ MM_Map( 0, 0 ); // IVT / BDA
+ for(i=0x10;i<0x9F;i++) {
+ MM_Map( i * 0x1000, i * 0x1000 ); MM_DerefPhys( i * 0x1000 );
+ }
+ MM_Map( 0x9F000, 0x9F000 ); // Stack / EBDA
+ MM_Allocate( 0x100000 ); // System Stack / Stub
+
+ *(Uint8*)(0x100000) = VM8086_OP_IRET;
+ *(Uint8*)(0x100001) = 0x07; // POP ES
+ *(Uint8*)(0x100002) = 0x1F; // POP DS
+ *(Uint8*)(0x100003) = 0xCB; // RET FAR
+
+ rmstack = (Uint16*)(VM8086_STACK_SEG*16 + VM8086_STACK_OFS);
+ *rmstack-- = 0xFFFF; //CS
+ *rmstack-- = 0x0010; //IP
+
+ // Setup Stack
+ stacksetup = (Uint*)0x101000;
+ *--stacksetup = VM8086_STACK_SEG; // GS
+ *--stacksetup = VM8086_STACK_SEG; // FS
+ *--stacksetup = VM8086_STACK_SEG; // DS
+ *--stacksetup = VM8086_STACK_SEG; // ES
+ *--stacksetup = VM8086_STACK_SEG; // SS
+ *--stacksetup = VM8086_STACK_OFS-2; // SP
+ *--stacksetup = 0x20202; // FLAGS
+ *--stacksetup = 0xFFFF; // CS
+ *--stacksetup = 0x10; // IP
+ *--stacksetup = 0xAAAA; // AX
+ *--stacksetup = 0xCCCC; // CX
+ *--stacksetup = 0xDDDD; // DX
+ *--stacksetup = 0xBBBB; // BX
+ *--stacksetup = 0x5454; // SP
+ *--stacksetup = 0xB4B4; // BP
+ *--stacksetup = 0x5151; // SI
+ *--stacksetup = 0xD1D1; // DI
+ *--stacksetup = 0x20|3; // DS - Kernel
+ *--stacksetup = 0x20|3; // ES - Kernel
+ *--stacksetup = 0x20|3; // FS
+ *--stacksetup = 0x20|3; // GS
+ __asm__ __volatile__ (
+ "mov %%eax,%%esp;\n\t" // Set stack pointer
+ "pop %%gs;\n\t"
+ "pop %%fs;\n\t"
+ "pop %%es;\n\t"
+ "pop %%ds;\n\t"
+ "popa;\n\t"
+ "iret;\n\t" : : "a" (stacksetup));
+ for(;;); // Shouldn't be reached
+ }
+
+ gVM8086_WorkerPID = pid;
+ Log_Log("VM8086", "gVM8086_WorkerPID = %i", pid);
+ Threads_Yield(); // Yield to allow the child to initialise
+
+ return MODULE_ERR_OK;
+}
+
+void VM8086_GPF(tRegs *Regs)
+{
+ Uint8 opcode;
+
+ //Log_Log("VM8086", "GPF - %04x:%04x", Regs->cs, Regs->eip);
+
+ if(Regs->eip == VM8086_MAGIC_IP && Regs->cs == VM8086_MAGIC_CS
+ && Threads_GetPID() == gVM8086_WorkerPID)
+ {
+ if( gpVM8086_State ) {
+ gpVM8086_State->AX = Regs->eax; gpVM8086_State->CX = Regs->ecx;
+ gpVM8086_State->DX = Regs->edx; gpVM8086_State->BX = Regs->ebx;
+ gpVM8086_State->BP = Regs->ebp;
+ gpVM8086_State->SI = Regs->esi; gpVM8086_State->DI = Regs->edi;
+ gpVM8086_State->DS = Regs->ds; gpVM8086_State->ES = Regs->es;
+ gpVM8086_State = NULL;
+ Threads_WakeTID(gVM8086_CallingThread);
+ }
+
+ //Log_Log("VM8086", "Waiting for something to do");
+ __asm__ __volatile__ ("sti");
+ // Wait for a new task
+ while(!gpVM8086_State) {
+ Threads_Sleep();
+ //Log_Log("VM8086", "gpVM8086_State = %p", gpVM8086_State);
+ }
+
+ //Log_Log("VM8086", "We have a task (%p)", gpVM8086_State);
+ Regs->esp -= 2; *(Uint16*)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = VM8086_MAGIC_CS;
+ Regs->esp -= 2; *(Uint16*)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = VM8086_MAGIC_IP;
+ Regs->esp -= 2; *(Uint16*)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = gpVM8086_State->CS;
+ Regs->esp -= 2; *(Uint16*)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = gpVM8086_State->IP;
+ Regs->esp -= 2; *(Uint16*)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = gpVM8086_State->DS;
+ Regs->esp -= 2; *(Uint16*)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = gpVM8086_State->ES;
+
+ // Set Registers
+ Regs->eip = 0x11; Regs->cs = 0xFFFF;
+ Regs->eax = gpVM8086_State->AX; Regs->ecx = gpVM8086_State->CX;
+ Regs->edx = gpVM8086_State->DX; Regs->ebx = gpVM8086_State->BX;
+ Regs->esi = gpVM8086_State->SI; Regs->edi = gpVM8086_State->DI;
+ Regs->ebp = gpVM8086_State->BP;
+ Regs->ds = 0x23; Regs->es = 0x23;
+ Regs->fs = 0x23; Regs->gs = 0x23;
+ return ;
+ }
+
+ opcode = *(Uint8*)( KERNEL_BASE + (Regs->cs*16) + (Regs->eip) );
+ Regs->eip ++;
+ switch(opcode)
+ {
+ case VM8086_OP_PUSHF: //PUSHF
+ Regs->esp -= 2;
+ *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) ) = Regs->eflags & 0xFFFF;
+ #if TRACE_EMU
+ Log_Debug("VM8086", "Emulated PUSHF");
+ #endif
+ break;
+ case VM8086_OP_POPF: //POPF
+ Regs->eflags &= 0xFFFF0002;
+ Regs->eflags |= *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) ) & 0xFFFD; // Changing IF is not allowed
+ Regs->esp += 2;
+ #if TRACE_EMU
+ Log_Debug("VM8086", "Emulated POPF");
+ #endif
+ break;
+
+ case VM8086_OP_INT_I: //INT imm8
+ {
+ int id;
+ id = *(Uint8*)( Regs->cs*16 +(Regs->eip&0xFFFF));
+ Regs->eip ++;
+
+ Regs->esp -= 2; *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) ) = Regs->cs;
+ Regs->esp -= 2; *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) ) = Regs->eip;
+
+ Regs->cs = *(Uint16*)(4*id + 2);
+ Regs->eip = *(Uint16*)(4*id);
+ #if TRACE_EMU
+ Log_Debug("VM8086", "Emulated INT 0x%x", id);
+ #endif
+ }
+ break;
+
+ case VM8086_OP_IRET: //IRET
+ Regs->eip = *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) ); Regs->esp += 2;
+ Regs->cs = *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) ); Regs->esp += 2;
+ #if TRACE_EMU
+ Log_Debug("VM8086", "IRET to %04x:%04x", Regs->cs, Regs->eip);
+ #endif
+ break;
+
+
+ case VM8086_OP_IN_AD: //IN AL, DX
+ Regs->eax &= 0xFFFFFF00;
+ Regs->eax |= inb(Regs->edx&0xFFFF);
+ #if TRACE_EMU
+ Log_Debug("VM8086", "Emulated IN AL, DX (Port 0x%x)\n", Regs->edx&0xFFFF);
+ #endif
+ break;
+ case VM8086_OP_IN_ADX: //IN AX, DX
+ Regs->eax &= 0xFFFF0000;
+ Regs->eax |= inw(Regs->edx&0xFFFF);
+ #if TRACE_EMU
+ Log_Debug("VM8086", "Emulated IN AX, DX (Port 0x%x)\n", Regs->edx&0xFFFF);
+ #endif
+ break;
+
+ case 0xEE: //OUT DX, AL
+ outb(Regs->edx&0xFFFF, Regs->eax&0xFF);
+ #if TRACE_EMU
+ Log_Debug("VM8086", "Emulated OUT DX, AL (*0x%04x = 0x%02x)\n", Regs->edx&0xFFFF, Regs->eax&0xFF);
+ #endif
+ break;
+ case 0xEF: //OUT DX, AX
+ outw(Regs->edx&0xFFFF, Regs->eax&0xFFFF);
+ #if TRACE_EMU
+ Log_Debug("VM8086", "Emulated OUT DX, AX (*0x%04x = 0x%04x)\n", Regs->edx&0xFFFF, Regs->eax&0xFFFF);
+ #endif
+ break;
+
+ // TODO: Decide on allowing VM8086 Apps to enable/disable interrupts
+ case 0xFA: //CLI
+ break;
+ case 0xFB: //STI
+ break;
+
+ case 0x66:
+ Log_Warning("VM8086", "Code at %04x:%04x attempted to use an operand override, ignored",
+ Regs->cs, Regs->eip);
+ break;
+
+ default:
+ Log_Error("VM8086", "Error - Unknown opcode %02x caused a GPF at %04x:%04x",
+ opcode, Regs->cs, Regs->eip);
+ // Force an end to the call
+ Regs->cs = VM8086_MAGIC_CS;
+ Regs->eip = VM8086_MAGIC_IP;
+ break;
+ }
+}
+
+/**
+ * \brief Create an instance of the VM8086 Emulator
+ */
+tVM8086 *VM8086_Init(void)
+{
+ tVM8086 *ret;
+ ret = calloc( 1, sizeof(tVM8086) + sizeof(struct sVM8086_InternalData) );
+ ret->Internal = (void*)((tVAddr)ret + sizeof(tVM8086));
+ return ret;
+}
+
+void VM8086_Free(tVM8086 *State)
+{
+ int i;
+ for( i = VM8086_PAGES_PER_INST; i --; )
+ MM_UnmapHWPages( State->Internal->AllocatedPages[i].VirtBase, 1);
+ free(State);
+}
+
+void *VM8086_Allocate(tVM8086 *State, int Size, Uint16 *Segment, Uint16 *Offset)
+{
+ int i, j, base = 0;
+ int nBlocks, rem;
+
+ Size = (Size + 127) & ~127;
+ nBlocks = Size / 128;
+
+ if(Size > 4096) return NULL;
+
+ for( i = 0; i < VM8086_PAGES_PER_INST; i++ )
+ {
+ if( State->Internal->AllocatedPages[i].VirtBase == 0 ) continue;
+
+
+ //Log_Debug("VM8086", "AllocatedPages[%i].Bitmap = 0b%b", i, State->Internal->AllocatedPages[i].Bitmap);
+
+ rem = nBlocks;
+ base = 0;
+ // Scan the bitmap for a free block
+ for( j = 0; j < 32; j++ ) {
+ if( State->Internal->AllocatedPages[i].Bitmap & (1 << j) ) {
+ base = j;
+ rem = nBlocks;
+ }
+ else {
+ rem --;
+ if(rem == 0) // Goodie, there's a gap
+ {
+ for( j = 0; j < nBlocks; j++ )
+ State->Internal->AllocatedPages[i].Bitmap |= 1 << (base + j);
+ *Segment = State->Internal->AllocatedPages[i].PhysAddr / 16 + base * 8;
+ *Offset = 0;
+ //Log_Debug("VM8086", "Allocated at #%i,%04x", i, base*128);
+ return (void*)( State->Internal->AllocatedPages[i].VirtBase + base * 128 );
+ }
+ }
+ }
+ }
+
+ // No pages with free space?, allocate a new one
+ for( i = 0; i < VM8086_PAGES_PER_INST; i++ )
+ {
+ if( State->Internal->AllocatedPages[i].VirtBase == 0 ) break;
+ }
+ // Darn, we can't allocate any more
+ if( i == VM8086_PAGES_PER_INST ) {
+ Log_Warning("VM8086", "Out of pages in %p", State);
+ return NULL;
+ }
+
+ State->Internal->AllocatedPages[i].VirtBase = MM_AllocDMA(
+ 1, 20, &State->Internal->AllocatedPages[i].PhysAddr);
+ State->Internal->AllocatedPages[i].Bitmap = 0;
+
+ for( j = 0; j < nBlocks; j++ )
+ State->Internal->AllocatedPages[i].Bitmap |= 1 << j;
+ //Log_Debug("VM8086", "AllocatedPages[%i].Bitmap = 0b%b", i, State->Internal->AllocatedPages[i].Bitmap);
+ *Segment = State->Internal->AllocatedPages[i].PhysAddr / 16;
+ *Offset = 0;
+ return (void*) State->Internal->AllocatedPages[i].VirtBase;
+}
+
+void *VM8086_GetPointer(tVM8086 *State, Uint16 Segment, Uint16 Offset)
+{
+ return (void*)( KERNEL_BASE + Segment*16 + Offset );
+}
+
+void VM8086_Int(tVM8086 *State, Uint8 Interrupt)
+{
+ State->IP = *(Uint16*)(KERNEL_BASE+4*Interrupt);
+ State->CS = *(Uint16*)(KERNEL_BASE+4*Interrupt+2);
+
+ LOCK( &glVM8086_Process );
+
+ gpVM8086_State = State;
+ gVM8086_CallingThread = Threads_GetTID();
+ Threads_WakeTID( gVM8086_WorkerPID );
+ while( gpVM8086_State != NULL )
+ Threads_Sleep();
+
+ RELEASE( &glVM8086_Process );
+}
}\r
\r
// Read Program Header Table\r
- phtab = malloc(sizeof(Elf32_Phdr)*hdr.phentcount);\r
+ phtab = malloc( sizeof(Elf32_Phdr) * hdr.phentcount );\r
+ if( !phtab ) {\r
+ LEAVE('n');\r
+ return NULL;\r
+ }\r
+ LOG("hdr.phoff = 0x%08x", hdr.phoff);\r
VFS_Seek(fp, hdr.phoff, SEEK_SET);\r
VFS_Read(fp, sizeof(Elf32_Phdr)*hdr.phentcount, phtab);\r
\r
for( i = 0; i < hdr.phentcount; i++ )\r
{\r
int lastSize;\r
- LOG("phtab[%i].Type = 0x%x", i, phtab[i].Type);\r
+ //LOG("phtab[%i].Type = 0x%x", i, phtab[i].Type);\r
+ LOG("phtab[%i] = {", i);\r
+ LOG(" .Type = 0x%08x", phtab[i].Type);\r
+ LOG(" .Offset = 0x%08x", phtab[i].Offset);\r
+ LOG(" .VAddr = 0x%08x", phtab[i].VAddr);\r
+ LOG(" .PAddr = 0x%08x", phtab[i].PAddr);\r
+ LOG(" .FileSize = 0x%08x", phtab[i].FileSize);\r
+ LOG(" .MemSize = 0x%08x", phtab[i].MemSize);\r
+ LOG(" .Flags = 0x%08x", phtab[i].Flags);\r
+ LOG(" .Align = 0x%08x", phtab[i].Align);\r
+ LOG(" }");\r
// Get Interpreter Name\r
if( phtab[i].Type == PT_INTERP )\r
{\r
\r
struct sElf32_Phdr {\r
Uint32 Type;\r
- Uint Offset;\r
- Uint VAddr;\r
- Uint PAddr;\r
+ Uint32 Offset;\r
+ Uint32 VAddr;\r
+ Uint32 PAddr;\r
Uint32 FileSize;\r
Uint32 MemSize;\r
Uint32 Flags;\r
int PE_Install(char **Arguments)\r
{\r
Binary_RegisterType(&gPE_Loader);\r
- return 1;\r
+ return MODULE_ERR_OK;\r
}\r
\r
/**\r
\r
// === IMPORTS ===\r
extern int Proc_Clone(Uint *Err, Uint Flags);\r
-extern void Threads_SetName(char *Name);\r
extern char *Threads_GetName(int ID);\r
extern void Threads_Exit(int, int);\r
extern Uint MM_ClearUser();\r
sTruePath = VFS_GetTruePath(file);\r
\r
if(sTruePath == NULL) {\r
- Warning("[BIN ] '%s' does not exist.", file);\r
+ Warning("[BIN ] '%s' does not exist.", file);\r
LEAVE('x', 0);\r
return 0;\r
}\r
return inb(GDB_SERIAL_PORT);
}
-static void E9(char ch)
+static void Debug_Putchar(char ch)
{
if(giDebug_KTerm != -1)
VFS_Write(giDebug_KTerm, 1, &ch);
#endif
}
-static void E9_Str(char *Str)
+static void Debug_Puts(char *Str)
{
- while(*Str) E9(*Str++);
+ while(*Str) Debug_Putchar(*Str++);
}
-void E9_Fmt(const char *format, va_list *args)
+void Debug_Fmt(const char *format, va_list *args)
{
char c, pad = ' ';
- int minSize = 0;
+ int minSize = 0, len;
char tmpBuf[34]; // For Integers
char *p = NULL;
int isLongLong = 0;
Uint64 arg;
+ int bPadLeft = 0;
while((c = *format++) != 0)
{
// Non control character
if( c != '%' ) {
- E9(c);
+ Debug_Putchar(c);
continue;
}
// Literal %
if(c == '%') {
- E9('%');
+ Debug_Putchar('%');
continue;
}
// Pointer
if(c == 'p') {
Uint ptr = va_arg(*args, Uint);
- E9('*'); E9('0'); E9('x');
+ Debug_Putchar('*'); Debug_Putchar('0'); Debug_Putchar('x');
p = tmpBuf;
itoa(p, ptr, 16, BITS/4, '0');
goto printString;
// Get Argument
arg = va_arg(*args, Uint);
+ // - Padding Side Flag
+ if(c == '+') {
+ bPadLeft = 1;
+ c = *format++;
+ }
+
// Padding
if(c == '0') {
pad = '0';
case 'd':
case 'i':
if( (isLongLong && arg >> 63) || (!isLongLong && arg >> 31) ) {
- E9('-');
+ Debug_Putchar('-');
arg = -arg;
}
itoa(p, arg, 10, minSize, pad);
itoa(p, arg, 2, minSize, pad);
goto printString;
+ printString:
+ if(!p) p = "(null)";
+ while(*p) Debug_Putchar(*p++);
+ break;
+
case 'B': //Boolean
- if(arg) E9_Str("True");
- else E9_Str("False");
+ if(arg) Debug_Puts("True");
+ else Debug_Puts("False");
break;
case 's':
p = (char*)(Uint)arg;
- printString:
if(!p) p = "(null)";
- while(*p) E9(*p++);
+ len = strlen(p);
+ if( !bPadLeft ) while(len++ < minSize) Debug_Putchar(pad);
+ while(*p) Debug_Putchar(*p++);
+ if( bPadLeft ) while(len++ < minSize) Debug_Putchar(pad);
break;
// Single Character / Array
case 'c':
if(minSize == 1) {
- E9(arg);
+ Debug_Putchar(arg);
break;
}
p = (char*)(Uint)arg;
if(!p) goto printString;
- while(minSize--) E9(*p++);
+ while(minSize--) Debug_Putchar(*p++);
break;
- default: E9(arg); break;
+ default:
+ Debug_Putchar(arg);
+ break;
}
}
}
-/**
- * \fn void LogV(char *Fmt, va_list Args)
- */
-void LogV(char *Fmt, va_list Args)
-{
- E9_Str("Log: ");
- E9_Fmt(Fmt, &Args);
- E9('\n');
-}
/**
* \fn void LogF(char *Msg, ...)
*/
va_start(args, Fmt);
- E9_Fmt(Fmt, &args);
+ Debug_Fmt(Fmt, &args);
va_end(args);
}
{
va_list args;
- E9_Str("Log: ");
+ Debug_Puts("Log: ");
va_start(args, Fmt);
- E9_Fmt(Fmt, &args);
+ Debug_Fmt(Fmt, &args);
va_end(args);
- E9('\n');
+ Debug_Putchar('\n');
}
void Warning(char *Fmt, ...)
{
va_list args;
- E9_Str("Warning: ");
+ Debug_Puts("Warning: ");
va_start(args, Fmt);
- E9_Fmt(Fmt, &args);
+ Debug_Fmt(Fmt, &args);
va_end(args);
- E9('\n');
+ Debug_Putchar('\n');
}
void Panic(char *Fmt, ...)
{
va_list args;
- E9_Str("Panic: ");
+ Debug_Puts("Panic: ");
va_start(args, Fmt);
- E9_Fmt(Fmt, &args);
+ Debug_Fmt(Fmt, &args);
va_end(args);
- E9('\n');
+ Debug_Putchar('\n');
Threads_Dump();
if(giDebug_KTerm != -1)
VFS_Close(giDebug_KTerm);
giDebug_KTerm = VFS_Open(File, VFS_OPENFLAG_WRITE);
- Log("Opened '%s' as 0x%x", File, giDebug_KTerm);
+ Log_Log("Debug", "Opened '%s' as 0x%x", File, giDebug_KTerm);
}
void Debug_Enter(char *FuncName, char *ArgTypes, ...)
va_start(args, ArgTypes);
- while(i--) E9(' ');
+ while(i--) Debug_Putchar(' ');
- E9_Str(FuncName); E9_Str(": (");
+ Debug_Puts(FuncName); Debug_Puts(": (");
while(*ArgTypes)
{
pos = strpos(ArgTypes, ' ');
if(pos != -1) ArgTypes[pos] = '\0';
if(pos == -1 || pos > 1) {
- E9_Str(ArgTypes+1);
- E9('=');
+ Debug_Puts(ArgTypes+1);
+ Debug_Putchar('=');
}
if(pos != -1) ArgTypes[pos] = ' ';
switch(*ArgTypes)
{
- case 'p': E9_Fmt("%p", &args); break;
- case 's': E9_Fmt("'%s'", &args); break;
- case 'i': E9_Fmt("%i", &args); break;
- case 'u': E9_Fmt("%u", &args); break;
- case 'x': E9_Fmt("0x%x", &args); break;
- case 'b': E9_Fmt("0b%b", &args); break;
+ case 'p': Debug_Fmt("%p", &args); break;
+ case 's': Debug_Fmt("'%s'", &args); break;
+ case 'i': Debug_Fmt("%i", &args); break;
+ case 'u': Debug_Fmt("%u", &args); break;
+ case 'x': Debug_Fmt("0x%x", &args); break;
+ case 'b': Debug_Fmt("0b%b", &args); break;
// Extended (64-Bit)
- case 'X': E9_Fmt("0x%llx", &args); break;
- case 'B': E9_Fmt("0b%llb", &args); break;
+ case 'X': Debug_Fmt("0x%llx", &args); break;
+ case 'B': Debug_Fmt("0b%llb", &args); break;
}
if(pos != -1) {
- E9(','); E9(' ');
+ Debug_Putchar(','); Debug_Putchar(' ');
}
if(pos == -1) break;
}
va_end(args);
- E9(')'); E9('\n');
+ Debug_Putchar(')'); Debug_Putchar('\n');
}
void Debug_Log(char *FuncName, char *Fmt, ...)
va_start(args, Fmt);
- while(i--) E9(' ');
+ while(i--) Debug_Putchar(' ');
- E9_Str(FuncName); E9_Str(": ");
- E9_Fmt(Fmt, &args);
+ Debug_Puts(FuncName); Debug_Puts(": ");
+ Debug_Fmt(Fmt, &args);
va_end(args);
- E9('\n');
+ Debug_Putchar('\n');
}
void Debug_Leave(char *FuncName, char RetType, ...)
i = 0;
}
// Indenting
- while(i--) E9(' ');
+ while(i--) Debug_Putchar(' ');
- E9_Str(FuncName); E9_Str(": RETURN");
+ Debug_Puts(FuncName); Debug_Puts(": RETURN");
// No Return
if(RetType == '-') {
- E9('\n');
+ Debug_Putchar('\n');
return;
}
- E9(' ');
+ Debug_Putchar(' ');
switch(RetType)
{
- case 'n': E9_Str("NULL"); break;
- case 'p': E9_Fmt("%p", &args); break;
- case 's': E9_Fmt("'%s'", &args); break;
- case 'i': E9_Fmt("%i", &args); break;
- case 'u': E9_Fmt("%u", &args); break;
- case 'x': E9_Fmt("0x%x", &args); break;
+ case 'n': Debug_Puts("NULL"); break;
+ case 'p': Debug_Fmt("%p", &args); break;
+ case 's': Debug_Fmt("'%s'", &args); break;
+ case 'i': Debug_Fmt("%i", &args); break;
+ case 'u': Debug_Fmt("%u", &args); break;
+ case 'x': Debug_Fmt("0x%x", &args); break;
// Extended (64-Bit)
- case 'X': E9_Fmt("0x%llx", &args); break;
+ case 'X': Debug_Fmt("0x%llx", &args); break;
}
- E9('\n');
+ Debug_Putchar('\n');
va_end(args);
}
{
Uint8 *cdat = Data;
Uint pos = 0;
- E9_Str(Header);
+ Debug_Puts(Header);
LogF(" (Hexdump of %p)\n", Data);
while(Length >= 16)
Length--;
cdat ++;
}
- E9('\n');
+ Debug_Putchar('\n');
}
// --- EXPORTS ---
* DMA Driver\r
*/\r
#include <acess.h>\r
+#include <modules.h>\r
\r
#define DMA_SIZE (0x2400)\r
#define DMA_ADDRESS(c) ((c)*DMA_SIZE+0x500) //Save Space for IDT and BDA\r
#define HIB(x) (((x)>>8)&0xFF)\r
#define HIW(x) (((x)>>16)&0xFFFF)\r
\r
-typedef struct {\r
- int mode;\r
+// === TYPES ===\r
+typedef struct\r
+{\r
+ int mode;\r
char *address;\r
} t_dmaChannel;\r
\r
+// === PROTOTYPES ===\r
+ int DMA_Install();\r
+void DMA_SetChannel(int Channel, int length, int read);\r
+ int DMA_ReadData(int channel, int count, void *buffer);\r
+\r
+// === CONSTANTS ===\r
const Uint8 cMASKPORT [8] = { 0x0A, 0x0A, 0x0A, 0x0A, 0xD4, 0xD4, 0xD4, 0xD4 };\r
const Uint8 cMODEPORT [8] = { 0x0B, 0x0B, 0x0B, 0x0B, 0xD6, 0xD6, 0xD6, 0xD6 };\r
const Uint8 cCLEARPORT[8] = { 0x0C, 0x0C, 0x0C, 0x0C, 0xD8, 0xD8, 0xD8, 0xD8 };\r
const Uint8 cADDRPORT [8] = { 0x00, 0x02, 0x04, 0x06, 0xC0, 0xC4, 0xC8, 0xCC };\r
const Uint8 cCOUNTPORT[8] = { 0x01, 0x03, 0x05, 0x07, 0xC2, 0xC6, 0xCA, 0xCE };\r
\r
+// === GLOBALS ===\r
+MODULE_DEFINE(0, 0x0100, ISADMA, DMA_Install, NULL, NULL);\r
char *dma_addresses[8];\r
t_dmaChannel dma_channels[8];\r
\r
+// === CODE ===\r
/**\r
- * \fn void DMA_Install()\r
+ * \fn int DMA_Install()\r
* \brief Initialise DMA channels\r
*/\r
-void DMA_Install()\r
+int DMA_Install()\r
{\r
Uint i;\r
for(i=8;i--;)\r
dma_addresses[i] = (char*)DMA_ADDRESS(i);\r
dma_addresses[i] += KERNEL_BASE;\r
}\r
+ return MODULE_ERR_OK;\r
}\r
\r
/**\r
memcpy(buffer, dma_addresses[channel], count);\r
return 0;\r
}\r
+\r
+/**\r
+ * \fn void DMA_WriteData(int channel, int count, void *buffer)\r
+ * \brief Write data to a DMA buffer\r
+ */\r
+int DMA_WriteData(int channel, int count, void *buffer)\r
+{\r
+ if(channel < 0 || channel > 7)\r
+ return -1;\r
+ if(count < 0 || count > DMA_SIZE)\r
+ return -2;\r
+ \r
+ memcpy(dma_addresses[channel], buffer, count);\r
+ \r
+ return 0;\r
+}\r
int FIFO_Install(char **Options)
{
DevFS_AddDevice( &gFIFO_DriverInfo );
- return MODULE_INIT_SUCCESS;
+ return MODULE_ERR_OK;
}
/**
// === CONSTANTS ===
#define KB_BUFFER_SIZE 1024
+#define USE_KERNEL_MAGIC 1
// === IMPORTS ===
void Threads_Dump();
temp = inb(0x61);
outb(0x61, temp | 0x80);
outb(0x61, temp & 0x7F);
+ inb(0x60); // Clear keyboard buffer
IRQ_AddHandler(1, KB_IRQHandler);
DevFS_AddDevice( &gKB_DevInfo );
//Log("KB_Install: Installed");
- return 1;
+ return MODULE_ERR_OK;
}
/**
Uint32 ch;
// int keyNum;
- //if( inportb(0x64) & 0x20 ) return;
+ // Check port 0x64 to tell if this is from the aux port
+ //if( inb(0x64) & 0x20 ) return;
scancode = inb(0x60); // Read from the keyboard's data buffer
-
- //Log("KB_IRQHandler: scancode = 0x%02x", scancode);
+ //Log_Debug("Keyboard", "scancode = %02x", scancode);
// Ignore ACKs
if(scancode == 0xFA) {
- // Oh man! This is anachic (I'm leaving it here to represent the
- // mess that Acess once was)
+ // Oh man! This is anarchic (I'm leaving it here to represent
+ // the mess that Acess once was)
//kb_lastChar = KB_ACK;
return;
}
//keyNum = giKB_KeyLayer * 256 + scancode;
// Check for unknown key
if(!ch && !gbKB_KeyUp)
- Warning("UNK %i %x", giKB_KeyLayer, scancode);
+ Log_Warning("Keyboard", "UNK %i %x", giKB_KeyLayer, scancode);
// Key Up?
if (gbKB_KeyUp)
// --- Check for Kernel Magic Combos
#if USE_KERNEL_MAGIC
- if(ch == KEY_LCTRL) gbKB_MagicState |= 1;
- if(ch == KEY_LALT) gbKB_MagicState |= 2;
+ if(ch == KEY_LCTRL) {
+ gbKB_MagicState |= 1;
+ //Log_Log("Keyboard", "Kernel Magic LCTRL Down\n");
+ }
+ if(ch == KEY_LALT) {
+ gbKB_MagicState |= 2;
+ //Log_Log("Keyboard", "Kernel Magic LALT Down\n");
+ }
if(gbKB_MagicState == 3)
{
switch(ch)
*/\r
#define DEBUG 0\r
#include <acess.h>\r
+#include <modules.h>\r
#include <vfs.h>\r
#include <fs_devfs.h>\r
#include <drv_pci.h>\r
#define LIST_DEVICES 1\r
\r
// === STRUCTURES ===\r
-typedef struct s_pciDevice {\r
+typedef struct sPCIDevice\r
+{\r
Uint16 bus, slot, fcn;\r
Uint16 vendor, device;\r
union {\r
- struct {Uint8 class, subclass;};\r
+ struct {\r
+ Uint8 class, subclass;\r
+ };\r
Uint16 oc;\r
};\r
Uint16 revision;\r
Uint32 ConfigCache[256/4];\r
char Name[8];\r
tVFS_Node Node;\r
-} t_pciDevice;\r
+} tPCIDevice;\r
\r
// === CONSTANTS ===\r
#define SPACE_STEP 5\r
Uint32 PCI_GetBAR5(int id);\r
Uint16 PCI_AssignPort(int id, int bar, int count);\r
\r
- int PCI_EnumDevice(Uint16 bus, Uint16 dev, Uint16 fcn, t_pciDevice *info);\r
+ int PCI_EnumDevice(Uint16 bus, Uint16 dev, Uint16 fcn, tPCIDevice *info);\r
Uint32 PCI_CfgReadDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset);\r
void PCI_CfgWriteDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset, Uint32 data);\r
Uint16 PCI_CfgReadWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset);\r
Uint8 PCI_CfgReadByte(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset);\r
\r
// === GLOBALS ===\r
-//MODULE_DEFINE(0, 0x0100, PCI, PCI_Install, NULL);\r
+MODULE_DEFINE(0, 0x0100, PCI, PCI_Install, NULL, NULL);\r
int giPCI_BusCount = 1;\r
int giPCI_InodeHandle = -1;\r
int giPCI_DeviceCount = 0;\r
-t_pciDevice *gPCI_Devices = NULL;\r
+tPCIDevice *gPCI_Devices = NULL;\r
tDevFS_Driver gPCI_DriverStruct = {\r
NULL, "pci",\r
{\r
{\r
int bus, dev, fcn, i;\r
int space = 0;\r
- t_pciDevice devInfo;\r
+ tPCIDevice devInfo;\r
void *tmpPtr = NULL;\r
\r
// Build Portmap\r
gaPCI_PortBitmap[i] = -1;\r
for( i = 0; i < MAX_RESERVED_PORT % 32; i ++ )\r
gaPCI_PortBitmap[MAX_RESERVED_PORT / 32] = 1 << i;\r
- //LogF("Done.\n");\r
\r
// Scan Busses\r
for( bus = 0; bus < giPCI_BusCount; bus++ )\r
{\r
- for( dev = 0; dev < 10; dev++ ) // 10 Devices per bus\r
+ for( dev = 0; dev < 32; dev++ ) // 32 Devices per bus\r
{\r
- for( fcn = 0; fcn < 8; fcn++ ) // 8 functions per device\r
+ for( fcn = 0; fcn < 8; fcn++ ) // Max 8 functions per device\r
{\r
// Check if the device/function exists\r
if(!PCI_EnumDevice(bus, dev, fcn, &devInfo))\r
- {\r
continue;\r
- }\r
\r
if(giPCI_DeviceCount == space)\r
{\r
space += SPACE_STEP;\r
- tmpPtr = realloc(gPCI_Devices, space*sizeof(t_pciDevice));\r
+ tmpPtr = realloc(gPCI_Devices, space*sizeof(tPCIDevice));\r
if(tmpPtr == NULL)\r
break;\r
gPCI_Devices = tmpPtr;\r
if(devInfo.oc == PCI_OC_PCIBRIDGE)\r
{\r
#if LIST_DEVICES\r
- Log("[PCI ] Bridge @ %i,%i:%i (0x%x:0x%x)",\r
+ Log_Log("PCI", "Bridge @ %i,%i:%i (0x%x:0x%x)",\r
bus, dev, fcn, devInfo.vendor, devInfo.device);\r
#endif\r
giPCI_BusCount++;\r
}\r
+ else\r
+ {\r
+ #if LIST_DEVICES\r
+ Log_Log("PCI", "Device %i,%i:%i %04x => 0x%04x:0x%04x",\r
+ bus, dev, fcn, devInfo.oc, devInfo.vendor, devInfo.device);\r
+ #endif\r
+ }\r
+ \r
devInfo.Node.Inode = giPCI_DeviceCount;\r
- memcpy(&gPCI_Devices[giPCI_DeviceCount], &devInfo, sizeof(t_pciDevice));\r
+ memcpy(&gPCI_Devices[giPCI_DeviceCount], &devInfo, sizeof(tPCIDevice));\r
giPCI_DeviceCount ++;\r
- #if LIST_DEVICES\r
- Log("[PCI ] Device %i,%i:%i => 0x%x:0x%x",\r
- bus, dev, fcn, devInfo.vendor, devInfo.device);\r
- #endif\r
\r
// WTF is this for?\r
+ // Maybe bit 23 must be set for the device to be valid?\r
+ // - Actually, maybe 23 means that there are sub-functions\r
if(fcn == 0) {\r
if( !(devInfo.ConfigCache[3] & 0x800000) )\r
break;\r
if(tmpPtr != gPCI_Devices)\r
break;\r
}\r
- tmpPtr = realloc(gPCI_Devices, giPCI_DeviceCount*sizeof(t_pciDevice));\r
+ \r
+ if(giPCI_DeviceCount == 0)\r
+ return MODULE_ERR_NOTNEEDED;\r
+ \r
+ tmpPtr = realloc(gPCI_Devices, giPCI_DeviceCount*sizeof(tPCIDevice));\r
if(tmpPtr == NULL)\r
- return 0;\r
+ return MODULE_ERR_MALLOC;\r
gPCI_Devices = tmpPtr;\r
- //LogF("Done.\n");\r
\r
- // Complete Driver Structure \r
+ // Complete Driver Structure\r
gPCI_DriverStruct.RootNode.Size = giPCI_DeviceCount;\r
\r
// And add to DevFS\r
DevFS_AddDevice(&gPCI_DriverStruct);\r
\r
- return 1;\r
+ return MODULE_ERR_OK;\r
}\r
\r
/**\r
\r
for( ; i < giPCI_DeviceCount; i++ )\r
{\r
- if((gPCI_Devices[i].oc & mask) != class) continue;\r
- return i;\r
+ if((gPCI_Devices[i].oc & mask) == class)\r
+ return i;\r
}\r
return -1;\r
}\r
Uint16 portVals;\r
int gran=0;\r
int i, j;\r
- t_pciDevice *dev;\r
+ tPCIDevice *dev;\r
\r
//LogF("PCI_AssignPort: (id=%i,bar=%i,count=%i)\n", id, bar, count);\r
\r
}\r
\r
/**\r
- * \fn int PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, t_pciDevice *info)\r
+ * \fn int PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, tPCIDevice *info)\r
*/\r
-int PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, t_pciDevice *info)\r
+int PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, tPCIDevice *info)\r
{\r
Uint16 vendor;\r
int i;\r
.FindDir = SysFS_Comm_FindDir
}
};
-// Root of the SysFS tree (just used for clean code)
+// Root of the SysFS tree (just used to keep the code clean)
tSysFS_Ent gSysFS_Root = {
NULL, NULL,
NULL,
.Size = 1,
.ImplPtr = &gSysFS_Version,
.ImplInt = (Uint)&gSysFS_Root // Self-Link
- // .NumACLs = 1,
- // .ACLs = &gVFS_ACL_EveryoneRX,
- // .Flags = VFS_FFLAG_DIRECTORY,
- // .ReadDir = SysFS_Comm_ReadDir,
- // .FindDir = SysFS_Comm_FindDir
}
};
tDevFS_Driver gSysFS_DriverInfo = {
int SysFS_Install(char **Options)
{
DevFS_AddDevice( &gSysFS_DriverInfo );
- return MODULE_INIT_SUCCESS;
+ return MODULE_ERR_OK;
}
/**
ent->Node.Size ++;
else
gSysFS_DriverInfo.RootNode.Size ++;
- Log("[SYSFS] Added directory '%s'", child->Name);
+ Log_Log("SysFS", "Added directory '%s'", child->Name);
}
ent = child;
break;
}
if( child ) {
- Warning("[SYSFS] '%s' is taken (in '%s')\n", &Path[start], Path);
+ Log_Warning("SysFS", "'%s' is taken (in '%s')\n", &Path[start], Path);
return 0;
}
child->ListNext = gSysFS_FileList;
gSysFS_FileList = child;
- Log("[SYSFS] Added '%s' (%p)", Path, Data);
+ Log_Log("SysFS", "Added '%s' (%p)", Path, Data);
return child->Node.Inode;
}
if( ent == file ) break;
}
if(!ent) {
- Warning("[SYSFS] Bookkeeping Error: File in list, but not in directory");
+ Log_Warning("SysFS", "Bookkeeping Error: File in list, but not in directory");
return 0;
}
// Install DevFS
DevFS_AddDevice( &gVGA_DevInfo );
- return 1;
+ return MODULE_ERR_OK;
}
/**
#define VT_SCROLLBACK 1 // 2 Screens of text
#define DEFAULT_OUTPUT "VGA"
//#define DEFAULT_OUTPUT "BochsGA"
+//#define DEFAULT_OUTPUT "Vesa"
#define DEFAULT_INPUT "PS2Keyboard"
#define DEFAULT_WIDTH 80
#define DEFAULT_HEIGHT 25
int Flags; //!< Flags (see VT_FLAG_*)
short Width; //!< Virtual Width
short Height; //!< Virtual Height
- short RealWidth; //!< Real Width
- short RealHeight; //!< Real Height
int ViewPos; //!< View Buffer Offset (Text Only)
int WritePos; //!< Write Buffer Offset (Text Only)
Uint32 CurColour; //!< Current Text Colour
- char Name[2]; //!< Name of the terminal
int InputRead; //!< Input buffer read position
int InputWrite; //!< Input buffer write position
tVT_Char *Text;
Uint32 *Buffer;
};
+ char Name[2]; //!< Name of the terminal
tVFS_Node Node;
} tVTerm;
// --- Terminals ---
tVTerm gVT_Terminals[NUM_VTS];
int giVT_CurrentTerminal = 0;
+// --- Video State ---
+short giVT_RealWidth; //!< Real Width
+short giVT_RealHeight; //!< Real Height
+ int gbVT_TextMode = 1;
// --- Driver Handles ---
char *gsVT_OutputDevice = NULL;
char *gsVT_InputDevice = NULL;
if(!gsVT_OutputDevice) gsVT_OutputDevice = "/Devices/"DEFAULT_OUTPUT;
if(!gsVT_InputDevice) gsVT_InputDevice = "/Devices/"DEFAULT_INPUT;
- LOG("Using '%s' as output", gsVT_OutputDevice);
- LOG("Using '%s' as input", gsVT_InputDevice);
+ Log_Log("VTerm", "Using '%s' as output", gsVT_OutputDevice);
+ Log_Log("VTerm", "Using '%s' as input", gsVT_InputDevice);
// Create Nodes
for( i = 0; i < NUM_VTS; i++ )
// Set kernel output to VT0
Debug_SetKTerminal("/Devices/VTerm/0");
- return MODULE_INIT_SUCCESS;
+ return MODULE_ERR_OK;
}
/**
VT_int_PutString(term, Buffer, Length);
break;
case TERM_MODE_FB:
- if( term->RealWidth > term->Width || term->RealHeight > term->Height )
+ if( giVT_RealWidth > term->Width || giVT_RealHeight > term->Height )
{
#if 0
int x, y, h;
return -1;
}
-/**
- * \fn void VT_SetTerminal(int ID)
- * \brief Set the current terminal
- */
-void VT_SetTerminal(int ID)
+void VT_SetResolution(int IsTextMode, int Width, int Height)
{
tVideo_IOCtl_Mode mode = {0};
- int modeNum;
+ int tmp;
// Create the video mode
- mode.width = gVT_Terminals[ ID ].Width;
- mode.height = gVT_Terminals[ ID ].Height;
- // - Text Mode
- if(gVT_Terminals[ ID ].Mode == TERM_MODE_TEXT) {
- mode.bpp = 12;
- mode.flags = VIDEO_FLAG_TEXT;
- }
- // - Framebuffer or 3D
- else {
- mode.bpp = 32;
- mode.flags = 0;
- }
+ mode.width = Width;
+ mode.height = Height;
+ mode.bpp = 32;
+ mode.flags = 0;
// Set video mode
VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_FINDMODE, &mode );
- modeNum = mode.id;
- gVT_Terminals[ ID ].RealWidth = mode.width;
- gVT_Terminals[ ID ].RealHeight = mode.height;
- VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_GETSETMODE, &modeNum );
+ tmp = mode.id;
+ giVT_RealWidth = mode.width;
+ giVT_RealHeight = mode.height;
+ VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_GETSETMODE, &tmp );
+
+
+ if(IsTextMode)
+ tmp = VIDEO_BUFFMT_TEXT;
+ else
+ tmp = VIDEO_BUFFMT_FRAMEBUFFER;
+ VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_SETBUFFORMAT, &tmp );
+}
+
+/**
+ * \fn void VT_SetTerminal(int ID)
+ * \brief Set the current terminal
+ */
+void VT_SetTerminal(int ID)
+{
// Update current terminal ID
- Log("Changed terminal from %i to %i", giVT_CurrentTerminal, ID);
+ Log_Log("VTerm", "Changed terminal from %i to %i", giVT_CurrentTerminal, ID);
giVT_CurrentTerminal = ID;
// Update the screen
if( Term->Mode == TERM_MODE_TEXT )
{
- if(UpdateAll) {
- VFS_WriteAt(
- giVT_OutputDevHandle,
- 0,
- Term->Width*Term->Height*sizeof(tVT_Char),
- &Term->Text[Term->ViewPos]
- );
- } else {
- int pos = Term->WritePos - Term->WritePos % Term->Width;
- VFS_WriteAt(
- giVT_OutputDevHandle,
- (pos - Term->ViewPos)*sizeof(tVT_Char),
- Term->Width*sizeof(tVT_Char),
- &Term->Text[pos]
- );
+ if(gbVT_TextMode)
+ {
+ if(UpdateAll) {
+ VFS_WriteAt(
+ giVT_OutputDevHandle,
+ 0,
+ Term->Width*Term->Height*sizeof(tVT_Char),
+ &Term->Text[Term->ViewPos]
+ );
+ } else {
+ int pos = Term->WritePos - Term->WritePos % Term->Width;
+ VFS_WriteAt(
+ giVT_OutputDevHandle,
+ (pos - Term->ViewPos)*sizeof(tVT_Char),
+ Term->Width*sizeof(tVT_Char),
+ &Term->Text[pos]
+ );
+ }
+ }
+ else
+ {
+ //TODO: Do VT Rendered Text
+ #if 0
+ if( UpdateAll ) {
+ VT_RenderText(0, Term->Width*Term->Height, &Term->Text[Term->ViewPos]);
+ }
+ else {
+ int pos = Term->WritePos - Term->WritePos % Term->Width;
+ VT_RenderText(
+ pos - Term->ViewPos,
+ Term->Width,
+ &Term->Text[pos]
+ );
+ }
+ #endif
}
}
else
// Alignment Check
if( head->Size & (BLOCK_SIZE-1) ) {
#if WARNINGS
- Warning("Size of heap address %p is invalid not aligned (0x%x)", head, head->Size);
+ Log_Warning("Heap", "Size of heap address %p is invalid not aligned (0x%x)", head, head->Size);
Heap_Dump();
#endif
RELEASE(&glHeap);
// Error check
if(head->Magic != MAGIC_FREE) {
#if WARNINGS
- Warning("Magic of heap address %p is invalid (0x%x)", head, head->Magic);
+ Log_Warning("Heap", "Magic of heap address %p is invalid (0x%x)", head, head->Magic);
Heap_Dump();
#endif
RELEASE(&glHeap); // Release spinlock
head->Magic = MAGIC_USED;
RELEASE(&glHeap); // Release spinlock
#if DEBUG_TRACE
- LOG("RETURN %p, to %p", best->Data, __builtin_return_address(0));
+ Log("[Heap ] Malloc'd %p (%i bytes), returning to %p", head->Data, head->Size, __builtin_return_address(0));
#endif
- return best->Data;
+ return head->Data;
}
// Break out of loop
if(best->Size == Bytes) {
RELEASE(&glHeap); // Release spinlock
#if DEBUG_TRACE
- LOG("RETURN %p, to %p", best->Data, __builtin_return_address(0));
+ Log("[Heap ] Malloc'd %p (%i bytes), returning to %p", best->Data, best->Size, __builtin_return_address(0));
#endif
return best->Data;
}
RELEASE(&glHeap); // Release spinlock
#if DEBUG_TRACE
- LOG("RETURN %p, to %p", best->Data, __builtin_return_address(0));
+ Log("[Heap ] Malloc'd %p (%i bytes), returning to %p", best->Data, best->Size, __builtin_return_address(0));
#endif
return best->Data;
}
tHeapFoot *foot;
#if DEBUG_TRACE
- LOG("Ptr = %p", Ptr);
- LOG("Returns to %p", __builtin_return_address(0));
+ Log_Log("Heap", "free: Ptr = %p", Ptr);
+ Log_Log("Heap", "free: Returns to %p", __builtin_return_address(0));
#endif
// Alignment Check
if( (Uint)Ptr & (sizeof(Uint)-1) ) {
- Warning("free - Passed a non-aligned address (%p)", Ptr);
+ Log_Warning("Heap", "free - Passed a non-aligned address (%p)", Ptr);
return;
}
// Sanity check
if((Uint)Ptr < (Uint)gHeapStart || (Uint)Ptr > (Uint)gHeapEnd)
{
- Warning("free - Passed a non-heap address (%p)\n", Ptr);
+ Log_Warning("Heap", "free - Passed a non-heap address (%p < %p < %p)\n",
+ gHeapStart, Ptr, gHeapEnd);
return;
}
// Check memory block - Header
head = (void*)( (Uint)Ptr - sizeof(tHeapHead) );
if(head->Magic == MAGIC_FREE) {
- Warning("free - Passed a freed block (%p) by %p", head, __builtin_return_address(0));
+ Log_Warning("Heap", "free - Passed a freed block (%p) by %p", head, __builtin_return_address(0));
return;
}
if(head->Magic != MAGIC_USED) {
- Warning("free - Magic value is invalid (%p, 0x%x)\n", head, head->Magic);
+ Log_Warning("Heap", "free - Magic value is invalid (%p, 0x%x)\n", head, head->Magic);
return;
}
// Check memory block - Footer
foot = (void*)( (Uint)head + head->Size - sizeof(tHeapFoot) );
if(foot->Head != head) {
- Warning("free - Footer backlink is incorrect (%p, 0x%x)\n", head, foot->Head);
+ Log_Warning("Heap", "free - Footer backlink is incorrect (%p, 0x%x)\n", head, foot->Head);
return;
}
if(foot->Magic != MAGIC_FOOT) {
- Warning("free - Footer magic is invalid (%p, %p = 0x%x)\n", head, &foot->Magic, foot->Magic);
+ Log_Warning("Heap", "free - Footer magic is invalid (%p, %p = 0x%x)\n", head, &foot->Magic, foot->Magic);
return;
}
/**
* \fn int IsHeap(void *Ptr)
- * \brief Checks if an address is a heap address
+ * \brief Checks if an address is a heap pointer
*/
int IsHeap(void *Ptr)
{
tHeapHead *head;
if((Uint)Ptr < (Uint)gHeapStart) return 0;
if((Uint)Ptr > (Uint)gHeapEnd) return 0;
+ if((Uint)Ptr & (sizeof(Uint)-1)) return 0;
head = (void*)( (Uint)Ptr - sizeof(tHeapHead) );
if(head->Magic != MAGIC_USED && head->Magic != MAGIC_FREE)
while( (Uint)head < (Uint)gHeapEnd )
{
foot = (void*)( (Uint)head + head->Size - sizeof(tHeapFoot) );
- Log("%p (0x%x): 0x%08lx 0x%lx", head, MM_GetPhysAddr((Uint)head), head->Size, head->Magic);
- Log("%p 0x%lx", foot->Head, foot->Magic);
- Log("");
+ Log_Log("Heap", "%p (0x%x): 0x%08lx 0x%lx", head, MM_GetPhysAddr((Uint)head), head->Size, head->Magic);
+ Log_Log("Heap", "%p 0x%lx", foot->Head, foot->Magic);
+ Log_Log("Heap", "");
// Sanity Check Header
if(head->Size == 0) {
- Log("HALTED - Size is zero");
+ Log_Warning("Heap", "HALTED - Size is zero");
break;
}
if(head->Size & (BLOCK_SIZE-1)) {
- Log("HALTED - Size is malaligned");
+ Log_Warning("Heap", "HALTED - Size is malaligned");
break;
}
if(head->Magic != MAGIC_FREE && head->Magic != MAGIC_USED) {
- Log("HALTED - Head Magic is Bad");
+ Log_Warning("Heap", "HALTED - Head Magic is Bad");
break;
}
// Check footer
if(foot->Magic != MAGIC_FOOT) {
- Log("HALTED - Foot Magic is Bad");
+ Log_Warning("Heap", "HALTED - Foot Magic is Bad");
break;
}
if(head != foot->Head) {
- Log("HALTED - Footer backlink is invalid");
+ Log_Warning("Heap", "HALTED - Footer backlink is invalid");
break;
}
#define NULL ((void*)0)
#define PACKED __attribute__ ((packed))
+#include <stdint.h>
#include <arch.h>
#include <stdarg.h>
#include "errno.h"
// --- IRQs ---
extern int IRQ_AddHandler(int Num, void (*Callback)(int));
+// --- Logging ---
+extern void Log_KernelPanic(char *Ident, char *Message, ...);
+extern void Log_Panic(char *Ident, char *Message, ...);
+extern void Log_Error(char *Ident, char *Message, ...);
+extern void Log_Warning(char *Ident, char *Message, ...);
+extern void Log_Notice(char *Ident, char *Message, ...);
+extern void Log_Log(char *Ident, char *Message, ...);
+extern void Log_Debug(char *Ident, char *Message, ...);
+
// --- Debug ---
/**
* \name Debugging and Errors
* \param PAddr Physical address to map in
* \param Number Number of pages to map
*/
-extern tVAddr MM_MapHWPage(tPAddr PAddr, Uint Number);
+extern tVAddr MM_MapHWPages(tPAddr PAddr, Uint Number);
/**
* \brief Allocates DMA physical memory
* \param Pages Number of pages required
* \param VAddr Virtual address allocate by ::MM_MapHWPage or ::MM_AllocDMA
* \param Number Number of pages to free
*/
-extern void MM_UnmapHWPage(tVAddr VAddr, Uint Number);
+extern void MM_UnmapHWPages(tVAddr VAddr, Uint Number);
/**
* \brief Allocate a single physical page
* \return Physical address allocated
* \name Strings
* \{
*/
+extern int vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args);
extern int sprintf(char *__s, const char *__format, ...);
extern Uint strlen(const char *Str);
extern char *strcpy(char *__dest, const char *__src);
+extern char *strncpy(char *__dest, const char *__src, size_t max);
extern int strcmp(const char *__str1, const char *__str2);
extern int strncmp(const char *Str1, const char *Str2, size_t num);
extern int strucmp(const char *Str1, const char *Str2);
*/
extern Uint rand();
+extern int CallWithArgArray(void *Function, int NArgs, Uint *Args);
// --- Heap ---
/**
extern void Threads_Exit();
extern void Threads_Yield();
extern void Threads_Sleep();
+extern void Threads_WakeTID(tTID Thread);
extern tPID Threads_GetPID();
extern tTID Threads_GetTID();
extern tUID Threads_GetUID();
extern tGID Threads_GetGID();
extern int SpawnTask(tThreadFunction Function, void *Arg);
extern Uint *Threads_GetCfgPtr(int Id);
+extern int Threads_SetName(char *NewName);
/**
* \}
*/
--- /dev/null
+/**
+ * \file apidoc/arch_x86.h
+ * \brief x86(-64) Specific Functions
+ * \author John Hodge (thePowersGang)
+ *
+ * \section toc Table of Contents
+ * - \ref portio "Port IO"
+ * - \ref dma "DMA - Direct Memory Access"
+ *
+ * \section portio Port IO
+ * The x86 architecture has two memory spaces, the first is the system
+ * memory accessable using standard loads and stores. The second is the
+ * 16-bit IO Bus. This bus is accessed using the \a in and \a out opcodes
+ * and is used to configure devices attached to the system.
+ * A driver should not use \a in and \a out directly, but instead use
+ * the provided \a in* and \a out* functions to access the IO Bus.
+ * This allows the kernel to run a driver in userspace if requested without
+ * the binary needing to be altered.
+ *
+ * \section dma DMA - Direct Memory Access
+ */
+
+/**
+ * \name IO Bus Access
+ * \{
+ */
+extern Uint8 inb(Uint16 Port); //!< Read 1 byte from the IO Bus
+extern Uint16 inw(Uint16 Port); //!< Read 2 bytes from the IO Bus
+extern Uint32 inl(Uint16 Port); //!< Read 4 bytes from the IO Bus
+extern Uint64 inq(Uint16 Port); //!< Read 8 bytes from the IO Bus\
+
+extern void outb(Uint16 Port, Uint8 Value); //!< Write 1 byte to the IO Bus
+extern void outw(Uint16 Port, Uint16 Value); //!< Write 2 bytes to the IO Bus
+extern void outl(Uint16 Port, Uint32 Value); //!< Write 4 bytes to the IO Bus
+extern void outq(Uint16 Port, Uint64 Value); //!< Write 8 bytes to the IO Bus
+/**
+ * \}
+ */
* The documentation covers filesystem drivers, binary formats and the
* various device driver interface standards.
*
- * \section VFS
- * The core of Acess is the VFS, or Virtual File System. The VFS abstracts
- * away from the user the differences between different filesystems,
- * network protocols and types of hardware.
- * The core of the VFS is the concept of a VFS Node (represented by the
- * ::tVFS_Node type). A node defines a file (either a normal file, directory
- * or some device abstraction), it's attributes (size, flags, timestamps)
- * and the functions used to access and modify it.
- *
- * \subsection filesystems Filesystem Drivers
- * Acess filesystems register themselves with the VFS by calling
- * ::VFS_AddDriver with a ::tVFS_Driver structure that defines the driver's
- * name, flags and mount function.
- * Filesystem drivers take the
- *
- * \section binfmt Binary Formats
- * See binary.h
- *
- * \section drivers Device Drivers
+ * \section index "Sections"
+ * - \ref modules.h "Module Definitions"
+ * - Describes how a module is defined in Acess
+ * - \ref binary.h "Binary Formats"
+ * - Explains how to register a new binary format with the kernel
+ * - \ref vfs.h "VFS - The Virtual File System"
+ * - The VFS is the core of Acess's driver architecture
+ * - \ref drivers "Device Drivers"
+ * - Describes how drivers should use the VFS to expose themselves to the
+ * user.
+ * - Drivers for specific types of hardware must behave in the specific
+ * way described here.
+ *
+ * \page drivers Device Drivers
+ *
+ * \section toc Contents
+ * - \ref drvintro "Introduction"
+ * - \ref drv_misc "Miscelanious Devices"
+ * - \ref drv_video "Video Drivers"
+ *
+ * \section drvintro Introduction
* All Acess2 device drivers communicate with user-level (and other parts
* of the greater kernel) via the VFS. They register themselves in a similar
* way to how filesystem drivers do, however instead of registering with
* the VFS core, they register with a special filesystem driver called the
- * DevFS (fs_devfs.h). DevFS exports the ::DevFS_AddDevice function that
- * takes a ::tDevFS_Driver structure as an agument that defines the
- * driver's name and the VFS node of it's root. This root is used to
- * provide the user access to the driver's function via IOCtl calls and
- * by Read/Write calls. Drivers are also able to expose a readonly buffer
- * by using ProcDev, usually to provide state information (such as usage
- * statistics and other misc information)
+ * \ref fs_devfs.h "Device Filesystem" (devfs). The DevFS provides the
+ * ::DevFS_AddDevice function that takes a ::tDevFS_Driver structure as
+ * an agument. This structure specifies the driver's name and its root
+ * VFS node. This node is used to provide the user access to the
+ * driver's functions via IOCtl calls and Reading or Writing to the driver
+ * file. Drivers are also able to expose a readonly buffer by using
+ * \ref fs_proc.h ProcDev, usually to provide state information or device
+ * capabilities for the the user.
*
* The device driver interfaces are all based on the core specifcation
* in tpl_drv_common.h (Common Device Driver definitions).
* IOCtl calls and/or files (where allowed by the type specifcation) to
* their device's VFS layout.
*
+ * \subsection drv_misc Miscelanious Devices
+ * If a device type does not have a specifcation for it, the driver can
+ * identify itself as a miscelanious device by returning DRV_TYPE_MISC
+ * from \ref DRV_IOCTL_TYPE.
+ * A misc device must at least implement the IOCtl calls defined in the
+ * \ref tpl_drv_common.h "Common Device Driver definitions", allowing it
+ * to be identified easily by the user and for interfacing programs to
+ * utilise the DRV_IOCTL_LOOKUP call.
+ *
* \subsection drv_video Video Devices
* Video drivers are based on a framebuffer model (unless in 3D mode,
* which is not yet fully standardised, so should be ignored).
extern void DMA_SetChannel(int channel, int length, int read);
extern int DMA_ReadData(int channel, int count, void *buffer);
+extern int DMA_WriteData(int channel, int count, void *buffer);
#endif
-/*\r
- * Acess 2\r
- * PCI Bus Driver\r
- * drv_pci.h\r
+/**\r
+ * \file drv_pci.h\r
+ * \brief PCI Bus Driver\r
+ * \author John Hodge (thePowersGang)\r
*/\r
#ifndef _DRV_PCI_H\r
#define _DRV_PCI_H\r
\r
-enum e_PciClasses {\r
+/**\r
+ * \brief PCI Class Codes\r
+ */\r
+enum ePCIClasses\r
+{\r
PCI_CLASS_PRE20 = 0x00,\r
PCI_CLASS_STORAGE,\r
PCI_CLASS_NETWORK,\r
PCI_CLASS_SERIALBUS,\r
PCI_CLASS_MISC = 0xFF\r
};\r
-enum e_PciOverClasses {\r
+\r
+enum ePCIOverClasses\r
+{\r
PCI_OC_PCIBRIDGE = 0x0604,\r
PCI_OC_SCSI = 0x0100\r
};\r
\r
-\r
+/**\r
+ * \brief Count PCI Devices\r
+ * \r
+ * Counts the number of devices with specified Vendor and Device IDs\r
+ */\r
extern int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn);\r
+\r
extern int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx);\r
extern int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev);\r
extern Uint8 PCI_GetIRQ(int id);\r
/*
- * AcessOS Microkernel Version
+ * Acess2
* errno.h
*/
#ifndef _ERRNO_H
#define _ERRNO_H
-enum eErrorNums {
+enum eErrorNums
+{
EOK,
ENOSYS,
EINVAL,
ENOMEM,
- EACCES
+ EACCES,
+ ENOTFOUND,
+ EREADONLY,
+ ENOTIMPL
};
#endif
// === FUNCTIONS ===
/**
* \fn int DevFS_AddDevice(tDevFS_Driver *Dev)
- * \brief Registers a device in the Device filesystem
- * \param Dev Pointer to a persistant structure that represents the driver
+ * \brief Registers a device in the Device Filesystem
+ * \param Device Pointer to a persistant structure that represents the driver
* \return Boolean success
*/
-extern int DevFS_AddDevice(tDevFS_Driver *Dev);
+extern int DevFS_AddDevice(tDevFS_Driver *Device);
+
+/**
+ * \brief Unregisters a device with the Device Filesystem
+ */
+extern void DevFS_DelDevice(tDevFS_Driver *Device);
#endif
#ifndef _MBOOT_H
#define _MBOOT_H
+#define MULTIBOOT_MAGIC 0x2BADB002
+
// === TYPES ===
typedef struct {
Uint32 Flags;
* AcessOS 2
* - Module Loader
*/
+/**
+ * \file modules.h
+ * \brief Module Handling and Loader Definitions
+ * \author John Hodge (thePowersGang)
+ *
+ * This file serves two pourposes. First it defines the format for native
+ * Acess2 modules and the functions to create them.
+ * Second, it defines the structure and register function for new module
+ * loaders, allowing Acess to understand many different module / driver
+ * formats.
+ *
+ * Modules are defined by including this file in the module's main source
+ * file and using the ::MODULE_DEFINE macro to create the module header.
+ *
+ * To register a new module loader with the kernel, the loader module must
+ * create and populate an instance of ::tModuleLoader then pass it to
+ * ::Module_RegisterLoader
+ */
#ifndef _MODULE_H
#define _MODULE_H
+/**
+ * \brief Module header magic value
+ */
#define MODULE_MAGIC ('A'|('M'<<8)|('D'<<16)|('\2'<<24))
+/**
+ * \def MODULE_ARCH_ID
+ * \brief Architecture ID
+ */
// IA32 - Architecture 1
#if ARCHDIR == x86
# define MODULE_ARCH_ID 1
# error "Unknown architecture when determining MODULE_ARCH_ID ('" #ARCHDIR "')"
#endif
+/**
+ * \brief Define a module
+ * \param _flags Module Flags
+ * \param _ver Module Version
+ * \param _ident Unique Module Name
+ * \param _entry Module initialiser / entrypoint
+ * \param _deinit Module cleanup / unloader
+ * \param _deps NULL terminated list of this's module's dependencies
+ * Contains the identifiers of the required modules.
+ */
#define MODULE_DEFINE(_flags,_ver,_ident,_entry,_deinit,_deps...) \
char *EXPAND_CONCAT(_DriverDeps_,_ident)[]={_deps};\
tModule __attribute__ ((section ("KMODULES"),unused))\
{MODULE_MAGIC,MODULE_ARCH_ID,_flags,_ver,NULL,EXPAND_STR(_ident),\
_entry,_deinit,EXPAND_CONCAT(_DriverDeps_,_ident)}
-typedef struct sModule {
- Uint32 Magic;
- Uint8 Arch;
- Uint8 Flags;
- Uint16 Version;
- struct sModule *Next;
- char *Name;
- int (*Init)(char **Arguments);
- void (*Deinit)();
- char **Dependencies; // NULL Terminated List
-} __attribute__((packed)) tModule;
+/**
+ * \brief Module header
+ * \note There is no reason for a module to touch this structure beyond
+ * using ::MODULE_DEFINE to create it.
+ */
+typedef struct sModule
+{
+ Uint32 Magic; //!< Identifying magic value (See ::MODULE_MAGIC)
+ Uint8 Arch; //!< Achitecture ID (See ::MODULE_ARCH_ID)
+ Uint8 Flags; //!< Module Flags
+ Uint16 Version; //!< Module Version in Major.Minor 8.8 form
+ struct sModule *Next; //!< Next module in list (not to be touched by the driver)
+ char *Name; //!< Module Name/Identifier
+ int (*Init)(char **Arguments); //!< Module initialiser / entrypoint
+ void (*Deinit)(); //!< Cleanup Function
+ char **Dependencies; //!< NULL terminated list of dependencies
+} PACKED tModule;
-#define MODULE_INIT_SUCCESS 1
-#define MODULE_INIT_FAILURE 0
+/**
+ * \brief Return values for tModule.Init
+ */
+enum eModuleErrors
+{
+ MODULE_ERR_OK, //!< No Error
+ MODULE_ERR_MISC, //!< Misc Error
+ MODULE_ERR_NOTNEEDED, //!< Module not needed
+ MODULE_ERR_MALLOC, //!< Error with malloc/realloc/calloc
+
+ MODULE_ERR_MAX //!< Maximum defined error code
+};
/**
* \brief Module Loader definition
* Allows a module to extend the loader to recognise other module types
* E.g. EDI, UDI, Windows, Linux, ...
*/
-typedef struct sModuleLoader {
+typedef struct sModuleLoader
+{
struct sModuleLoader *Next; //!< Kernel Only - Next loader in list
char *Name; //!< Friendly name for the loader
int (*Detector)(void *Base); //!< Simple detector function
/**
* \brief Registers a tModuleLoader with the kernel
* \param Loader Pointer to loader structure (must be persistent)
+ * \return Boolean Success
*/
extern int Module_RegisterLoader(tModuleLoader *Loader);
// --- threads.c's
struct sThread *Next; //!< Next thread in list
tSpinlock IsLocked; //!< Thread's spinlock
- int Status; //!< Thread Status
+ volatile int Status; //!< Thread Status
int RetStatus; //!< Return Status
Uint TID; //!< Thread ID
* but they may choose not to allow direct user access to the framebuffer.\r
* \r
* \section Screen Contents\r
- * Reads and writes to the driver's file while in component colour modes\r
+ * Writes to the driver's file while in component colour modes\r
* must correspond to a change of the contents of the screen. The framebuffer\r
* must start at offset 0 in the file.\r
* In pallete colour modes the LFB is preceded by a 1024 byte pallete (allowing\r
* room for 256 entries of 32-bits each)\r
-*/\r
+ * Reading from the screen must either return zero, or read from the\r
+ * framebuffer.\r
+ * \r
+ * \section Mode Support\r
+ * All video drivers must support at least one text mode (Mode #0)\r
+ * For each graphics mode the driver exposes, there must be a corresponding\r
+ * text mode with the same resolution, this mode will be used when the\r
+ * user switches to a text Virtual Terminal while in graphics mode.\r
+ */\r
#ifndef _TPL_VIDEO_H\r
#define _TPL_VIDEO_H\r
\r
*/\r
VIDEO_IOCTL_MODEINFO,\r
\r
+ /**\r
+ * ioctl(..., int *NewFormat)\r
+ * \brief Switches between Text, Framebuffer and 3D modes\r
+ * \param NewFormat Pointer to the new format code (see eTplVideo_BufFormats)\r
+ * \return Original format\r
+ * \r
+ * Enabes and disables the video text mode, changing the behavior of\r
+ * writes to the device file.\r
+ */\r
+ VIDEO_IOCTL_SETBUFFORMAT,\r
+ \r
/**\r
* ioctl(..., tVideo_IOCtl_Pos *pos)\r
* \brief Sets the cursor position\r
Uint8 flags; //!< Mode Flags\r
} tVideo_IOCtl_Mode;\r
\r
-//! \name Video Mode flags\r
-//! \{\r
-/**\r
- * \brief Text Mode Flag\r
- * \note A text mode should have the ::sVideo_IOCtl_Mode.bpp set to 12\r
- */\r
-#define VIDEO_FLAG_TEXT 0x1\r
/**\r
- * \brief Slow (non-accellerated mode)\r
+ * \brief Buffer Format Codes\r
*/\r
-#define VIDEO_FLAG_SLOW 0x2\r
-//! \}\r
+enum eTplVideo_BufFormats\r
+{\r
+ VIDEO_BUFFMT_TEXT,\r
+ VIDEO_BUFFMT_FRAMEBUFFER,\r
+ VIDEO_BUFFMT_3DSTREAM\r
+};\r
\r
/**\r
* \brief Describes a position in the video framebuffer\r
/**
* \file vfs.h
* \brief Acess VFS Layer
+ *
+ * The Acess Virtual File System (VFS) provides abstraction of multiple
+ * physical filesystems, network storage and devices (both hardware and
+ * virtual) to the user.
+ *
+ * The core of the VFS is the concept of a \ref tVFS_Node "VFS Node".
+ * A VFS Node represents a "file" in the VFS tree, this can be any sort
+ * of file (an ordinary file, a directory, a symbolic link or a device)
+ * depending on the bits set in the \ref tVFS_Node.Flags Flags field.
+ * - For more information see "VFS Node Flags"
*/
#ifndef _VFS_H
#define _VFS_H
#include <acess.h>
/**
- * \name VFS Node Flags
+ * \name tVFS_Node Flags
+ * \brief Flag values for tVFS_Node.Flags
* \{
*/
-#define VFS_FFLAG_READONLY 0x01 //!< Read-only file
-#define VFS_FFLAG_DIRECTORY 0x02 //!< Directory
-#define VFS_FFLAG_SYMLINK 0x04 //!< Symbolic Link
+//! \todo Is this still needed
+#define VFS_FFLAG_READONLY 0x01 //!< Readonly File
+/**
+ * \brief Directory Flag
+ *
+ * This flag marks the tVFS_Node as describing a directory, and says
+ * that the tVFS_Node.FindDir, tVFS_Node.ReadDir, tVFS_Node.MkNod and
+ * tVFS_Node.Relink function pointers are valid.
+ * For a directory the tVFS_Node.Size field contains the number of files
+ * within the directory, or -1 for undetermined.
+ */
+#define VFS_FFLAG_DIRECTORY 0x02
+/**
+ * \brief Symbolic Link Flag
+ *
+ * Marks a file as a symbolic link
+ */
+#define VFS_FFLAG_SYMLINK 0x04
+/**
+ * \brief Set User ID Flag
+ *
+ * Allows an executable file to change it's executing user to the file's
+ * owner.
+ * In the case of a directory, it means that all immediate children will
+ * inherit the UID of the parent.
+ */
+#define VFS_FFLAG_SETUID 0x08
+/**
+ * \brief Set Group ID Flag
+ *
+ * Allows an executable file to change it's executing group to the file's
+ * owning group.
+ * In the case of a directory, it means that all immediate children will
+ * inherit the GID of the parent.
+ */
+#define VFS_FFLAG_SETGID 0x10
/**
* \}
*/
/**
* \brief VFS Node
- * \todo Complete / Finalise
+ *
+ * This structure provides the VFS with the functions required to read/write
+ * the file (or directory) that it represents.
*/
-typedef struct sVFS_Node {
- Uint64 Inode; //!< Inode ID
+typedef struct sVFS_Node
+{
+ /**
+ * \name Identifiers
+ * \brief Fields used by the driver to identify what data this node
+ * corresponds to.
+ * \{
+ */
+ Uint64 Inode; //!< Inode ID (Essentially another ImplInt)
Uint ImplInt; //!< Implementation Usable Integer
void *ImplPtr; //!< Implementation Usable Pointer
+ /**
+ * \}
+ */
+ /**
+ * \name Node State
+ * \brief Stores the misc information about the node
+ * \{
+ */
int ReferenceCount; //!< Number of times the node is used
Uint64 Size; //!< File Size
Uint32 Flags; //!< File Flags
+ /**
+ * Pointer to cached data (FS Specific)
+ * \note Inode_* will free when the node is uncached this if needed
+ */
+ void *Data;
+ /**
+ * \}
+ */
+
+ /**
+ * \name Times
+ * \{
+ */
Sint64 ATime; //!< Last Accessed Time
Sint64 MTime; //!< Last Modified Time
Sint64 CTime; //!< Creation Time
+ /**
+ * \}
+ */
- Uint UID; //!< Owning User
- Uint GID; //!< Owning Group
+ /**
+ * \name Access controll
+ * \{
+ */
+ tUID UID; //!< ID of Owning User
+ tGID GID; //!< ID of Owning Group
int NumACLs; //!< Number of ACL entries
- tVFS_ACL *ACLs; //!< ACL Entries
+ tVFS_ACL *ACLs; //!< Access Controll List pointer
+ /**
+ * \}
+ */
+ /**
+ * \name Common Functions
+ * \brief Functions that are used no matter the value of .Flags
+ * \{
+ */
/**
* \brief Reference the node
* \param Node Pointer to this node
*/
int (*IOCtl)(struct sVFS_Node *Node, int Id, void *Data);
+ /**
+ * }
+ */
+
+ /**
+ * \name Buffer Functions
+ * \brief Functions for accessing a buffer-type file (normal file or
+ * symbolic link)
+ * \{
+ */
+
/**
* \brief Read from the file
* \param Node Pointer to this node
*/
Uint64 (*Write)(struct sVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+ /**
+ * }
+ */
+
+ /**
+ * \name Directory Functions
+ * \{
+ */
/**
* \brief Find an directory entry by name
* \param Node Pointer to this node
* \param Node Pointer to this node
* \param OldName Name of the item to move/delete
* \param NewName New name (or NULL if unlinking is wanted)
- * \return Boolean Success
+ * \return Zero on Success, non-zero on error (see errno.h)
*/
int (*Relink)(struct sVFS_Node *Node, char *OldName, char *NewName);
+
+ /**
+ * }
+ */
} tVFS_Node;
/**
extern tVFS_Node NULLNode; //!< NULL VFS Node (Ignored/Skipped)
/**
- * \name Simple ACLs to aid writing drivers
+ * \name Static ACLs
+ * \brief Simple ACLs to aid writing drivers
* \{
*/
extern tVFS_ACL gVFS_ACL_EveryoneRWX; //!< Everyone Read/Write/Execute
extern tVFS_ACL *VFS_UnixToAcessACL(Uint Mode, Uint Owner, Uint Group);
// --- Node Cache --
-//! \name Node Cache
-//! \{
+/**
+ * \name Node Cache
+ * \brief Functions to allow a node to be cached in memory by the VFS
+ *
+ * These functions store a node for the driver, to prevent it from having
+ * to re-generate the node on each call to FindDir. It also allows for
+ * fast cleanup when a filesystem is unmounted.
+ * \{
+ */
/**
* \fn int Inode_GetHandle()
* \brief Gets a unique handle to the Node Cache
*/
extern tVFS_Node *Inode_CacheNode(int Handle, tVFS_Node *Node);
/**
- * \fn void Inode_UncacheNode(int Handle, Uint64 Inode)
+ * \fn int Inode_UncacheNode(int Handle, Uint64 Inode)
* \brief Dereferences (and removes if needed) a node from the cache
* \param Handle A handle returned by Inode_GetHandle()
* \param Inode Value of the Inode field of the ::tVFS_Node you want to remove
*/
extern void Inode_ClearCache(int Handle);
-//! \}
+/**
+ * \}
+ */
#endif
// === CONSTANTS ===
//! Maximum size of a Memory Path generated by VFS_GetMemPath
-#define VFS_MEMPATH_SIZE (3 + (BITS/8)*2)
+#define VFS_MEMPATH_SIZE (3 + (BITS/4)*2)
/**
* \name Flags for VFS_Open
* \{
#define UNIX_TO_2K ((30*365*3600*24) + (7*3600*24)) //Normal years + leap years
// === PROTOTYPES ===
+ int atoi(const char *string);
+void itoa(char *buf, Uint num, int base, int minLength, char pad);
+ int vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args);
+ int sprintf(char *__s, const char *__format, ...);
+ int tolower(int c);
+ int strucmp(const char *Str1, const char *Str2);
+ int strpos(const char *Str, char Ch);
+ Uint8 ByteSum(void *Ptr, int Size);
+size_t strlen(const char *__s);
+char *strcpy(char *__str1, const char *__str2);
+char *strncpy(char *__str1, const char *__str2, size_t max);
+ int strcmp(const char *str1, const char *str2);
+ int strncmp(const char *str1, const char *str2, size_t num);
+char *strdup(const char *Str);
+ int DivUp(int num, int dem);
+ int strpos8(const char *str, Uint32 Search);
int ReadUTF8(Uint8 *str, Uint32 *Val);
+ int WriteUTF8(Uint8 *str, Uint32 Val);
+Sint64 timestamp(int sec, int mins, int hrs, int day, int month, int year);
+Uint rand(void);
+ int CheckString(char *String);
+ int CheckMem(void *Mem, int NumBytes);
+ int ModUtil_LookupString(char **Array, char *Needle);
+ int ModUtil_SetIdent(char *Dest, char *Value);
+
+// === EXPORTS ===
+EXPORT(atoi);
+EXPORT(itoa);
+EXPORT(vsnprintf);
+EXPORT(sprintf);
+EXPORT(tolower);
+EXPORT(strucmp);
+EXPORT(strpos);
+EXPORT(ByteSum);
+EXPORT(strlen);
+EXPORT(strcpy);
+EXPORT(strncpy);
+EXPORT(strcmp);
+EXPORT(strncmp);
+EXPORT(strdup);
+EXPORT(DivUp);
+EXPORT(strpos8);
+EXPORT(ReadUTF8);
+EXPORT(WriteUTF8);
+EXPORT(timestamp);
+EXPORT(CheckString);
+EXPORT(CheckMem);
+EXPORT(ModUtil_LookupString);
+EXPORT(ModUtil_SetIdent);
// === GLOBALS ===
static Uint giRandomState = RANDOM_SEED;
int atoi(const char *string)
{
int ret = 0;
+ int bNeg = 0;
+
+ //Log("atoi: (string='%s')", string);
// Clear non-numeric characters
- while( !('0' <= *string && *string <= '9') ) string++;
+ while( !('0' <= *string && *string <= '9') && *string != '-' ) string++;
+ if( *string == '-' ) {
+ bNeg = 1;
+ while( !('0' <= *string && *string <= '9') ) string++;
+ }
if(*string == '0')
{
{
// Hex
string ++;
- for( ;; ) {
- ret *= 16;
- if('0' <= *string && *string <= '9')
+ for( ;; string ++ )
+ {
+ if('0' <= *string && *string <= '9') {
+ ret *= 16;
ret += *string - '0';
- else if('A' <= *string && *string <= 'F')
+ }
+ else if('A' <= *string && *string <= 'F') {
+ ret *= 16;
ret += *string - 'A' + 10;
- else if('a' <= *string && *string <= 'f')
+ }
+ else if('a' <= *string && *string <= 'f') {
+ ret *= 16;
ret += *string - 'a' + 10;
+ }
else
break;
- string ++;
}
}
- else
+ else // Octal
{
- for( ;; )
+ for( ; '0' <= *string && *string <= '7'; string ++ )
{
ret *= 8;
- if('0' <= *string && *string <= '7')
- ret += *string - '0';
- else
- break;
+ ret += *string - '0';
}
}
}
- else
+ else // Decimal
{
for( ; '0' <= *string && *string <= '9'; string++)
{
ret += *string - '0';
}
}
+
+ if(bNeg) ret = -ret;
+
+ //Log("atoi: RETURN %i", ret);
+
return ret;
}
buf[i] = 0;
}
-#define PUTCH(c) do{if(pos==__maxlen)break;if(__s){__s[pos++]=(c);}else{pos++;}}while(0)
+/**
+ * \brief Append a character the the vsnprintf output
+ */
+#define PUTCH(c) do{\
+ char ch=(c);\
+ if(pos==__maxlen){return pos;}\
+ if(__s){__s[pos++]=ch;}else{pos++;}\
+ }while(0)
int vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args)
{
char c, pad = ' ';
int isLongLong = 0;
Uint64 val;
size_t pos = 0;
+ // Flags
+ // int bPadLeft = 0;
+
+ //Log("vsnprintf: (__s=%p, __maxlen=%i, __format='%s', ...)", __s, __maxlen, __format);
while((c = *__format++) != 0)
{
if(c != '%') { PUTCH(c); continue; }
c = *__format++;
+ //Log("pos = %i", pos);
// Literal %
if(c == '%') { PUTCH('%'); continue; }
// Get Argument
val = va_arg(args, Uint);
+ //Log("val = %x", val);
// - Padding
if(c == '0') {
case 's':
p = (char*)(Uint)val;
printString:
+ //Log("p = '%s'", p);
if(!p) p = "(null)";
while(*p) PUTCH(*p++);
break;
if(__s && pos != __maxlen)
__s[pos] = '\0';
-
return pos;
}
* \brief Pseudo random number generator
* \note Unknown effectiveness (made up on the spot)
*/
-Uint rand()
+Uint rand(void)
{
Uint old = giRandomState;
// Get the next state value
strncpy(Dest, Value, 32);
return 1;
}
-
-EXPORT(strlen);
-EXPORT(strdup);
-EXPORT(strcmp);
-EXPORT(strncmp);
-EXPORT(strcpy);
-EXPORT(strncpy);
-
-EXPORT(timestamp);
-EXPORT(ReadUTF8);
-EXPORT(CheckMem);
-EXPORT(CheckString);
-EXPORT(ModUtil_LookupString);
-EXPORT(ModUtil_SetIdent);
--- /dev/null
+/*
+ * Acess 2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * logging.c - Kernel Logging Service
+ */
+#include <acess.h>
+
+#define PRINT_ON_APPEND 1
+
+// === CONSTANTS ===
+enum eLogLevels
+{
+ LOG_LEVEL_KPANIC,
+ LOG_LEVEL_PANIC,
+ LOG_LEVEL_FATAL,
+ LOG_LEVEL_ERROR,
+ LOG_LEVEL_WARNING,
+ LOG_LEVEL_NOTICE,
+ LOG_LEVEL_LOG,
+ LOG_LEVEL_DEBUG,
+ NUM_LOG_LEVELS
+};
+const char *csaLevelCodes[] = {"k","p","f","e","w","n","l","d"};
+
+// === TYPES ===
+typedef struct sLogEntry
+{
+ struct sLogEntry *Next;
+ struct sLogEntry *LevelNext;
+ Sint64 Time;
+ char Ident[8];
+ int Level;
+ int Length;
+ char Data[];
+} tLogEntry;
+typedef struct sLogList
+{
+ tLogEntry *Head;
+ tLogEntry *Tail;
+} tLogList;
+
+// === PROTOTYPES ===
+void Log_AddEvent(char *Ident, int Level, char *Format, va_list Args);
+static void Log_Int_PrintMessage(tLogEntry *Entry);
+void Log_KernelPanic(char *Ident, char *Message, ...);
+void Log_Panic(char *Ident, char *Message, ...);
+void Log_Error(char *Ident, char *Message, ...);
+void Log_Warning(char *Ident, char *Message, ...);
+void Log_Notice(char *Ident, char *Message, ...);
+void Log_Log(char *Ident, char *Message, ...);
+void Log_Debug(char *Ident, char *Message, ...);
+//static Uint64 Log_Int_GetIdent(const char *Str);
+
+// === EXPORTS ===
+EXPORT(Log_KernelPanic);
+EXPORT(Log_Panic);
+EXPORT(Log_Error);
+EXPORT(Log_Warning);
+EXPORT(Log_Notice);
+EXPORT(Log_Log);
+EXPORT(Log_Debug);
+
+// === GLOBALS ===
+tSpinlock glLog;
+tLogList gLog;
+tLogList gLog_Levels[NUM_LOG_LEVELS];
+
+// === CODE ===
+/**
+ * \brief Adds an event to the log
+ */
+void Log_AddEvent(char *Ident, int Level, char *Format, va_list Args)
+{
+ int len;
+ tLogEntry *ent;
+
+ if( Level >= NUM_LOG_LEVELS ) return;
+
+ len = vsnprintf(NULL, 256, Format, Args);
+
+ //Log("len = %i", len);
+
+ ent = malloc(sizeof(tLogEntry)+len+1);
+ ent->Time = now();
+ strncpy(ent->Ident, Ident, 7);
+ ent->Level = Level;
+ ent->Length = len;
+ vsnprintf( ent->Data, 256, Format, Args );
+
+ //Log("ent->Ident = '%s'", ent->Ident);
+ //Log("ent->Data = '%s'", ent->Data);
+
+ LOCK( &glLog );
+
+ ent->Next = gLog.Tail;
+ if(gLog.Head)
+ gLog.Tail = ent;
+ else
+ gLog.Tail = gLog.Head = ent;
+
+ ent->LevelNext = gLog_Levels[Level].Tail;
+ if(gLog_Levels[Level].Head)
+ gLog_Levels[Level].Tail = ent;
+ else
+ gLog_Levels[Level].Tail = gLog_Levels[Level].Head = ent;
+
+ RELEASE( &glLog );
+
+ #if PRINT_ON_APPEND
+ Log_Int_PrintMessage( ent );
+ #endif
+
+}
+
+/**
+ * \brief Prints a log message to the debug console
+ */
+void Log_Int_PrintMessage(tLogEntry *Entry)
+{
+ LogF("%018lli%s [%+8s] %s\n",
+ Entry->Time,
+ csaLevelCodes[Entry->Level],
+ Entry->Ident,
+ Entry->Data
+ );
+}
+
+/**
+ * \brief KERNEL PANIC!!!!
+ */
+void Log_KernelPanic(char *Ident, char *Message, ...)
+{
+ va_list args;
+ va_start(args, Message);
+ Log_AddEvent(Ident, LOG_LEVEL_KPANIC, Message, args);
+ va_end(args);
+}
+
+/**
+ * \brief Panic Message - Driver Unrecoverable error
+ */
+void Log_Panic(char *Ident, char *Message, ...)
+{
+ va_list args;
+ va_start(args, Message);
+ Log_AddEvent(Ident, LOG_LEVEL_PANIC, Message, args);
+ va_end(args);
+}
+
+/**
+ * \brief Error Message - Recoverable Error
+ */
+void Log_Error(char *Ident, char *Message, ...)
+{
+ va_list args;
+ va_start(args, Message);
+ Log_AddEvent(Ident, LOG_LEVEL_ERROR, Message, args);
+ va_end(args);
+}
+
+/**
+ * \brief Warning Message - Something the user should know
+ */
+void Log_Warning(char *Ident, char *Message, ...)
+{
+ va_list args;
+
+ va_start(args, Message);
+ Log_AddEvent(Ident, LOG_LEVEL_WARNING, Message, args);
+ va_end(args);
+}
+
+/**
+ * \brief Notice Message - Something the user might like to know
+ */
+void Log_Notice(char *Ident, char *Message, ...)
+{
+ va_list args;
+ va_start(args, Message);
+ Log_AddEvent(Ident, LOG_LEVEL_NOTICE, Message, args);
+ va_end(args);
+}
+
+/**
+ * \brief Log Message - Possibly useful information
+ */
+void Log_Log(char *Ident, char *Message, ...)
+{
+ va_list args;
+ va_start(args, Message);
+ Log_AddEvent(Ident, LOG_LEVEL_LOG, Message, args);
+ va_end(args);
+}
+
+/**
+ * \brief Debug Message - Only a developer would want this info
+ */
+void Log_Debug(char *Ident, char *Message, ...)
+{
+ va_list args;
+ va_start(args, Message);
+ Log_AddEvent(Ident, LOG_LEVEL_DEBUG, Message, args);
+ va_end(args);
+}
* Acess2
* - Module Loader
*/
+#define DEBUG 0
#include <acess.h>
#include <modules.h>
#define USE_EDI 0
-#define USE_UDI 1
+#define USE_UDI 0
// === PROTOTYPES ===
- int Modules_LoadBuiltins();
+ int Modules_LoadBuiltins(void);
+ int Module_RegisterLoader(tModuleLoader *Loader);
int Module_LoadMem(void *Buffer, Uint Length, char *ArgString);
int Module_LoadFile(char *Path, char *ArgString);
int Module_int_ResolveDeps(tModule *Info);
int Module_IsLoaded(char *Name);
+// === EXPORTS ===
+EXPORT(Module_RegisterLoader);
+
// === IMPORTS ===
#if USE_UDI
extern int UDI_LoadDriver(void *Base);
// === GLOBALS ===
int giNumBuiltinModules = 0;
- int giModuleSpinlock = 0;
+tSpinlock glModuleSpinlock;
tModule *gLoadedModules = NULL;
tModuleLoader *gModule_Loaders = NULL;
+tModule *gLoadingModules = NULL;
// === CODE ===
-int Modules_LoadBuiltins()
+/**
+ * \brief Initialises a module
+ * \param Module Pointer to the module header
+ * \return Zero on success, eModuleErrors or -1 on error
+ * \retval -1 Returned if a dependency fails, or a circular dependency
+ * exists.
+ * \retval 0 Returned on success
+ * \retval >0 Error code form the module's initialisation function
+ */
+int Module_int_Initialise(tModule *Module)
{
- int i, j, k;
- int numToInit = 0;
- Uint8 *baIsLoaded;
+ int i, j;
+ int ret;
char **deps;
+ tModule *mod;
- giNumBuiltinModules = (Uint)&gKernelModulesEnd - (Uint)&gKernelModules;
- giNumBuiltinModules /= sizeof(tModule);
+ ENTER("pModule", Module);
- baIsLoaded = calloc( giNumBuiltinModules, sizeof(*baIsLoaded) );
+ deps = Module->Dependencies;
- // Pass 1 - Are the dependencies compiled in?
- for( i = 0; i < giNumBuiltinModules; i++ )
+ // Check if the module has been loaded
+ for( mod = gLoadedModules; mod; mod = mod->Next )
{
- deps = gKernelModules[i].Dependencies;
- if(deps)
- {
- for( j = 0; deps[j]; j++ )
- {
- for( k = 0; k < giNumBuiltinModules; k++ ) {
- if(strcmp(deps[j], gKernelModules[k].Name) == 0)
- break;
- }
- if(k == giNumBuiltinModules) {
- Warning("Unable to find dependency '%s' for '%s' in kernel",
- deps[j], gKernelModules[i].Name);
-
- baIsLoaded[i] = -1; // Don't Load
- break;
- }
- }
- }
- numToInit ++;
+ if(mod == Module) LEAVE_RET('i', 0);
}
- // Pass 2 - Intialise
- while(numToInit)
+ // Add to the "loading" (prevents circular deps)
+ Module->Next = gLoadingModules;
+ gLoadingModules = Module;
+
+ // Scan dependency list
+ for( j = 0; deps && deps[j]; j++ )
{
- for( i = 0; i < giNumBuiltinModules; i++ )
+ // Check if the module is already loaded
+ for( mod = gLoadedModules; mod; mod = mod->Next )
{
- if( baIsLoaded[i] ) continue; // Ignore already loaded modules
+ if(strcmp(deps[j], mod->Name) == 0)
+ break;
+ }
+ if( mod ) continue; // Dependency is loaded, check the rest
- deps = gKernelModules[i].Dependencies;
-
- if( deps )
- {
- for( j = 0; deps[j]; j++ )
- {
- for( k = 0; k < giNumBuiltinModules; k++ ) {
- if(strcmp(deps[j], gKernelModules[k].Name) == 0)
- break;
- }
- // `k` is assumed to be less than `giNumBuiltinModules`
-
- // If a dependency failed, skip and mark as failed
- if( baIsLoaded[k] == -1 ) {
- baIsLoaded[i] = -1;
- numToInit --;
- break;
- }
- // If a dependency is not intialised, skip
- if( !baIsLoaded[k] ) break;
- }
- // Check if we broke out
- if( deps[j] ) continue;
- }
-
- // All Dependencies OK? Initialise
- StartupPrint(gKernelModules[i].Name);
- Log("Initialising %p '%s' v%i.%i...",
- &gKernelModules[i],
- gKernelModules[i].Name,
- gKernelModules[i].Version>>8, gKernelModules[i].Version & 0xFF
- );
- if( gKernelModules[i].Init(NULL) == 0 ) {
- Log("Loading Failed, all modules that depend on this will also fail");
- baIsLoaded[i] = -1;
- }
- // Mark as loaded
- else
- baIsLoaded[i] = 1;
- numToInit --;
+ // Ok, check if it's loading
+ for( mod = gLoadingModules->Next; mod; mod = mod->Next )
+ {
+ if(strcmp(deps[j], mod->Name) == 0)
+ break;
+ }
+ if( mod ) {
+ Log_Warning("Module", "Circular dependency detected");
+ LEAVE_RET('i', -1);
+ }
+
+ // So, if it's not loaded, we better load it then
+ for( i = 0; i < giNumBuiltinModules; i ++ )
+ {
+ if( strcmp(deps[j], gKernelModules[i].Name) == 0 )
+ break;
+ }
+ if( i == giNumBuiltinModules ) {
+ Log_Warning("Module", "Dependency '%s' for module '%s' failed");
+ return -1;
+ }
+
+ // Dependency is not loaded, so load it
+ ret = Module_int_Initialise( &gKernelModules[i] );
+ if( ret )
+ {
+ // The only "ok" error is NOTNEEDED
+ if(ret != MODULE_ERR_NOTNEEDED)
+ LEAVE_RET('i', -1);
+ }
+ }
+
+ // All Dependencies OK? Initialise
+ StartupPrint(Module->Name);
+ Log_Log("Module", "Initialising %p '%s' v%i.%i...",
+ Module, Module->Name,
+ Module->Version >> 8, Module->Version & 0xFF
+ );
+
+ ret = Module->Init(NULL);
+ if( ret != MODULE_ERR_OK ) {
+ switch(ret)
+ {
+ case MODULE_ERR_MISC:
+ Log_Warning("Module", "Unable to load, reason: Miscelanious");
+ break;
+ case MODULE_ERR_NOTNEEDED:
+ Log_Warning("Module", "Unable to load, reason: Module not needed");
+ break;
+ case MODULE_ERR_MALLOC:
+ Log_Warning("Module", "Unable to load, reason: Error in malloc/realloc/calloc, probably not good");
+ break;
+ default:
+ Log_Warning("Module", "Unable to load reason - Unknown code %i", ret);
+ break;
}
+ LEAVE_RET('i', ret);
+ return ret;
+ }
+
+ // Remove from loading list
+ gLoadingModules = gLoadingModules->Next;
+
+ // Add to loaded list
+ LOCK( &glModuleSpinlock );
+ Module->Next = gLoadedModules;
+ gLoadedModules = Module;
+ RELEASE( &glModuleSpinlock );
+
+ LEAVE_RET('i', 0);
+}
+
+/**
+ * \brief Initialises builtin modules
+ */
+int Modules_LoadBuiltins()
+{
+ int i;
+
+ // Count modules
+ giNumBuiltinModules = (Uint)&gKernelModulesEnd - (Uint)&gKernelModules;
+ giNumBuiltinModules /= sizeof(tModule);
+
+ for( i = 0; i < giNumBuiltinModules; i++ )
+ {
+ Module_int_Initialise( &gKernelModules[i] );
}
return 0;
// Error check
if(base == NULL) {
- Warning("Module_LoadFile: Unable to load '%s'", Path);
+ Log_Warning("Module", "Module_LoadFile - Unable to load '%s'", Path);
return 0;
}
// Unknown module type?, return error
Binary_Unload(base);
#if USE_EDI
- Warning("Module_LoadFile: Module has neither a Module Info struct, nor an EDI entrypoint");
+ Log_Warning("Module", "Module '%s' has neither a Module Info struct, nor an EDI entrypoint", Path);
#else
- Warning("Module_LoadFile: Module does not have a Module Info struct");
+ Log_Warning("Module", "Module '%s' does not have a Module Info struct", Path);
#endif
return 0;
}
// Check magic number
if(info->Magic != MODULE_MAGIC)
{
- Warning("Module_LoadFile: Module's magic value is invalid (0x%x != 0x%x)", info->Magic, MODULE_MAGIC);
+ Log_Warning("Module", "Module's magic value is invalid (0x%x != 0x%x)", info->Magic, MODULE_MAGIC);
return 0;
}
// Check Architecture
if(info->Arch != MODULE_ARCH_ID)
{
- Warning("Module_LoadFile: Module is for a different architecture");
+ Log_Warning("Module", "Module is for a different architecture");
return 0;
}
+ #if 1
+ if( Module_int_Initialise( info ) )
+ {
+ Binary_Unload(base);
+ return 0;
+ }
+ #else
// Resolve Dependencies
if( !Module_int_ResolveDeps(info) ) {
Binary_Unload(base);
return 0;
}
- Log("Initialising %p '%s' v%i.%i...",
+ Log_Log("Module", "Initialising %p '%s' v%i.%i...",
info,
info->Name,
info->Version>>8, info->Version & 0xFF
}
// Add to list
- LOCK( &giModuleSpinlock );
+ LOCK( &glModuleSpinlock );
info->Next = gLoadedModules;
gLoadedModules = info;
- RELEASE( &giModuleSpinlock );
+ RELEASE( &glModuleSpinlock );
+ #endif
return 1;
}
{
// Check if the module is loaded
if( !Module_IsLoaded(*names) ) {
- Warning("Module `%s' requires `%s', which is not loaded\n", Info->Name, *names);
+ Log_Warning("Module", "Module `%s' requires `%s', which is not loaded\n", Info->Name, *names);
return 0;
}
}
if( !Syscall_ValidString(Regs->Arg1)
|| !Syscall_Valid(sizeof(Uint), Regs->Arg2) ) {
err = -EINVAL;
- ret = -1;
+ ret = 0;
break;
}
// Path, *Entrypoint
#define DEBUG 0
#include <acess.h>
+#define N_VARIABLES 16
+#define N_MAX_ARGS BITS
+
// === TYPES ===
typedef struct
{
int nLines;
tConfigLine Lines[];
} tConfigFile;
+typedef struct
+{
+ char *Name; // Name
+ int MinArgs; // Minimum number of arguments
+ int MaxArgs; // Maximum number of arguments
+ Uint IntArgs; // Bitmap of arguments that should be treated as integers
+ void *Func; // Function pointer
+ Uint OptDefaults[N_MAX_ARGS]; // Default values for optional arguments
+} tConfigCommand;
// === IMPORTS ===
extern int Modules_LoadBuiltins();
-extern int PCI_Install();
+//extern int PCI_Install();
extern void DMA_Install();
extern void Debug_SetKTerminal(char *File);
extern void StartupPrint(char *Str);
void System_ExecuteScript();
tConfigFile *System_Int_ParseFile(char *File);
+// === CONSTANTS ===
+const tConfigCommand caConfigCommands[] = {
+ {"module", 1,2, 0, Module_LoadFile, {(Uint)"",0}}, // Load a module from a file
+ {"spawn", 1,1, 0, Proc_Spawn, {0}}, // Spawn a process
+ // --- VFS ---
+ {"mount", 3,4, 0, VFS_Mount, {(Uint)"",0}}, // Mount a device
+ {"symlink", 2,2, 0, VFS_Symlink, {0}}, // Create a Symbolic Link
+ {"mkdir", 1,1, 0, VFS_MkDir, {0}}, // Create a Directory
+ {"open", 1,2, 0, VFS_Open, {VFS_OPENFLAG_READ,0}}, // Open a file
+ {"close", 1,1, 0x1, VFS_Close, {0}}, // Close an open file
+ {"ioctl", 3,3, 0x3, VFS_IOCtl, {0}}, // Call an IOCtl
+
+ {"", 0,0, 0, NULL, {0}}
+};
+#define NUM_CONFIG_COMMANDS (sizeof(caConfigCommands)/sizeof(caConfigCommands[0]))
+
// === GLOBALS ===
char *gsConfigScript = "/Acess/Conf/BootConf.cfg";
// === CODE ===
void System_Init(char *ArgString)
{
- // - Start Builtin Drivers & Filesystems
- StartupPrint("Scanning PCI Bus...");
- PCI_Install();
- StartupPrint("Loading DMA...");
- DMA_Install();
- StartupPrint("Loading staticly compiled modules...");
- Modules_LoadBuiltins();
-
- // Set the debug to be echoed to the terminal
- StartupPrint("Kernel now echoes to VT6 (Ctrl-Alt-F7)");
- Debug_SetKTerminal("/Devices/VTerm/6");
// - Parse Kernel's Command Line
System_ParseCommandLine(ArgString);
// - Execute the Config Script
- Log("Executing config script...");
+ Log_Log("Config", "Executing config script...");
System_ExecuteScript();
+
+ // Set the debug to be echoed to the terminal
+ Log_Log("Config", "Kernel now echoes to VT7 (Ctrl-Alt-F8)");
+ Debug_SetKTerminal("/Devices/VTerm/7");
}
/**
int i;
char *str;
- Log("Kernel Command Line: \"%s\"", ArgString);
+ Log_Log("Config", "Kernel Invocation \"%s\"", ArgString);
// --- Get Arguments ---
str = ArgString;
for( argc = 0; argc < 32; argc++ )
{
- while(*str == ' ') str++; // Eat Whitespace
- if(*str == '\0') { argc--; break;} // End of string
+ // Eat Whitespace
+ while(*str == ' ') str++;
+ // Check for the end of the string
+ if(*str == '\0') { argc--; break;}
argv[argc] = str;
while(*str && *str != ' ')
{
}*/
str++;
}
- if(*str == '\0') break; // End of string
+ if(*str == '\0') break; // Check for EOS
*str = '\0'; // Cap off argument string
str ++; // and increment the string pointer
}
// Check if the equals was found
if( *value == '\0' ) {
- Warning("Expected '=' in the string '%s'", Arg);
+ Log_Warning("Config", "Expected '=' in the string '%s'", Arg);
return ;
}
// - Symbolic Link <link>=<destination>
if(value[0] == '/')
{
- Log("Symbolic link '%s' pointing to '%s'", Arg, value);
+ Log_Log("Config", "Symbolic link '%s' pointing to '%s'", Arg, value);
VFS_Symlink(Arg, value);
}
// - Mount <mountpoint>=<fs>:<device>
}
// Create Mountpoint
if( (fd = VFS_Open(Arg, 0)) == -1 ) {
- Log("Creating directory '%s'", Arg, value);
+ Log_Log("Config", "Creating directory '%s'", Arg, value);
VFS_MkDir( Arg );
} else {
VFS_Close(fd);
}
// Mount
- Log("Mounting '%s' to '%s' ('%s')", dev, Arg, value);
+ Log_Log("Config", "Mounting '%s' to '%s' ('%s')", dev, Arg, value);
VFS_Mount(dev, Arg, value, "");
}
}
// Check for boolean/flag (no '=')
if(*value == '\0')
{
- if(strcmp(Arg, "") == 0) {
- } else {
- Warning("Kernel flag '%s' is not recognised", Arg);
- }
+ //if(strcmp(Arg, "") == 0) {
+ //} else {
+ Log_Warning("Config", "Kernel flag '%s' is not recognised", Arg);
+ //}
}
else
{
value ++; // and eat it's position
if(strcmp(Arg, "SCRIPT") == 0) {
- Log("Config Script: '%s'", value);
- gsConfigScript = value;
+ Log_Log("Config", "Config Script: '%s'", value);
+ if(strlen(value) == 0)
+ gsConfigScript = NULL;
+ else
+ gsConfigScript = value;
} else {
- Warning("Kernel config setting '%s' is not recognised", Arg);
+ Log_Warning("Config", "Kernel config setting '%s' is not recognised", Arg);
}
}
{
int fp;
int fLen = 0;
- int i;
+ int i, j, k;
+ int val;
+ int result = 0;
+ int variables[N_VARIABLES];
+ int bReplaced[N_MAX_ARGS];
char *fData;
+ char *jmpTarget;
tConfigFile *file;
tConfigLine *line;
// Open Script
fp = VFS_Open(gsConfigScript, VFS_OPENFLAG_READ);
if(fp == -1) {
- Warning("[CFG] Passed script '%s' does not exist", gsConfigScript);
+ Log_Warning("Config", "Passed script '%s' does not exist", gsConfigScript);
return;
}
VFS_Close(fp);
-
// Parse File
file = System_Int_ParseFile(fData);
- // Loop lines
+ // Parse each line
for( i = 0; i < file->nLines; i++ )
{
line = &file->Lines[i];
if( line->nParts == 0 ) continue; // Skip blank
- // Mount
- if( strcmp(line->Parts[0], "mount") == 0 ) {
- if( line->nParts != 4 ) {
- Warning("Configuration command 'mount' requires 3 arguments, %i given",
- line->nParts-1);
- continue;
+ if(line->Parts[0][0] == ':') continue; // Ignore labels
+
+ // Prescan and eliminate variables
+ for( j = 1; j < line->nParts; j++ ) {
+ Log_Debug("Config", "Arg #%i is '%s'", j, line->Parts[j]);
+ bReplaced[j] = 0;
+ if( line->Parts[j][0] != '$' ) continue;
+ if( line->Parts[j][1] == '?' ) {
+ val = result;
}
- //Log("[CFG ] Mount '%s' to '%s' (%s)",
- // line->Parts[1], line->Parts[2], line->Parts[3]);
- //! \todo Use an optional 4th argument for the options string
- VFS_Mount(line->Parts[1], line->Parts[2], line->Parts[3], "");
- }
- // Module
- else if(strcmp(line->Parts[0], "module") == 0) {
- if( line->nParts < 2 || line->nParts > 3 ) {
- Warning("Configuration command 'module' requires 1 or 2 arguments, %i given",
- line->nParts-1);
- continue;
+ else {
+ val = atoi( &line->Parts[j][1] );
+ if( val < 0 || val > N_VARIABLES ) continue;
+ val = variables[ val ];
}
- if( line->nParts == 3 )
- Module_LoadFile(line->Parts[1], line->Parts[2]);
- else
- Module_LoadFile(line->Parts[1], "");
+ Log_Debug("Config", "Replaced arg %i ('%s') with 0x%x", j, line->Parts[j], val);
+ line->Parts[j] = malloc( BITS/8+2+1 );
+ sprintf(line->Parts[j], "0x%x", val);
+ bReplaced[j] = 1;
}
- // UDI Module
- else if(strcmp(line->Parts[0], "udimod") == 0) {
- if( line->nParts != 2 ) {
- Warning("Configuration command 'udimod' requires 1 argument, %i given",
- line->nParts-1);
- continue;
+
+ for( j = 0; j < NUM_CONFIG_COMMANDS; j++ )
+ {
+ Uint args[N_MAX_ARGS];
+ if(strcmp(line->Parts[0], caConfigCommands[j].Name) != 0) continue;
+
+ Log_Debug("Config", "Command '%s', %i args passed", line->Parts[0], line->nParts-1);
+
+ if( line->nParts - 1 < caConfigCommands[j].MinArgs ) {
+ Log_Warning("Config",
+ "Configuration command '%s' requires at least %i arguments, %i given",
+ caConfigCommands[j].Name, caConfigCommands[j].MinArgs, line->nParts-1
+ );
+ break;
}
- Log("[CFG ] Load UDI Module '%s'", line->Parts[1]);
- Module_LoadFile(line->Parts[1], "");
- }
- // EDI Module
- else if(strcmp(line->Parts[0], "edimod") == 0) {
- if( line->nParts != 2 ) {
- Warning("Configuration command 'edimod' requires 1 argument, %i given",
- line->nParts-1);
- continue;
+
+ if( line->nParts - 1 > caConfigCommands[j].MaxArgs ) {
+ Log_Warning("Config",
+ "Configuration command '%s' takes at most %i arguments, %i given",
+ caConfigCommands[j].Name, caConfigCommands[j].MaxArgs, line->nParts-1
+ );
+ break;
+ }
+
+ for( k = caConfigCommands[j].MaxArgs-1; k > line->nParts - 1; k-- ) {
+ args[k] = caConfigCommands[j].OptDefaults[k];
+ }
+
+ for( k = line->nParts-1; k--; )
+ {
+ if( caConfigCommands[j].IntArgs & (1 << k) ) {
+ args[k] = atoi(line->Parts[k+1]);
+ }
+ else {
+ args[k] = (Uint)line->Parts[k+1];
+ }
+ Log_Debug("Config", "args[%i] = 0x%x", k, args[k]);
}
- Log("[CFG ] Load EDI Module '%s'", line->Parts[1]);
- Module_LoadFile(line->Parts[1], "");
+ result = CallWithArgArray(caConfigCommands[j].Func, caConfigCommands[j].MaxArgs, args);
+ Log_Debug("Config", "result = %i", result);
+ break;
}
- // Symbolic Link
- else if(strcmp(line->Parts[0], "symlink") == 0) {
- if( line->nParts != 3 ) {
- Warning("Configuration command 'symlink' requires 2 arguments, %i given",
+ if( j < NUM_CONFIG_COMMANDS ) continue;
+
+ // --- State and Variables ---
+ if(strcmp(line->Parts[0], "set") == 0)
+ {
+ int to, value;
+ if( line->nParts-1 != 2 ) {
+ Log_Warning("Config", "Configuration command 'set' requires 2 arguments, %i given",
line->nParts-1);
continue;
}
- Log("[CFG ] Symlink '%s' pointing to '%s'",
- line->Parts[1], line->Parts[2]);
- VFS_Symlink(line->Parts[1], line->Parts[2]);
+
+ to = atoi(line->Parts[1]);
+ value = atoi(line->Parts[2]);
+
+ variables[to] = value;
+ result = value;
}
- // Create Directory
- else if(strcmp(line->Parts[0], "mkdir") == 0) {
- if( line->nParts != 2 ) {
- Warning("Configuration command 'mkdir' requires 1 argument, %i given",
+ // if <val1> <op> <val2> <dest>
+ else if(strcmp(line->Parts[0], "if") == 0)
+ {
+ if( line->nParts-1 != 4 ) {
+ Log_Warning("Config", "Configuration command 'if' requires 4 arguments, %i given",
line->nParts-1);
- continue;
}
- Log("[CFG ] New Directory '%s'", line->Parts[1]);
- VFS_MkDir(line->Parts[1]);
+
+ result = atoi(line->Parts[1]);
+ val = atoi(line->Parts[3]);
+
+ jmpTarget = line->Parts[4];
+
+ Log_Log("Config", "IF 0x%x %s 0x%x THEN GOTO %s",
+ result, line->Parts[2], val, jmpTarget);
+
+ if( strcmp(line->Parts[2], "<" ) == 0 ) {
+ if( result < val ) goto jumpToLabel;
+ }
+ else if( strcmp(line->Parts[2], "<=") == 0 ) {
+ if( result <= val ) goto jumpToLabel;
+ }
+ else if( strcmp(line->Parts[2], ">" ) == 0 ) {
+ if (result > val ) goto jumpToLabel;
+ }
+ else if( strcmp(line->Parts[2], ">=") == 0 ) {
+ if( result >= val ) goto jumpToLabel;
+ }
+ else if( strcmp(line->Parts[2], "=") == 0 ) {
+ if( result == val ) goto jumpToLabel;
+ }
+ else if( strcmp(line->Parts[2], "!=") == 0 ) {
+ if( result != val ) goto jumpToLabel;
+ }
+ else {
+ Log_Warning("Config", "Unknown comparision '%s' in `if`", line->Parts[2]);
+ }
+
}
- // Spawn a process
- else if(strcmp(line->Parts[0], "spawn") == 0) {
- if( line->nParts != 2 ) {
- Warning("Configuration command 'spawn' requires 1 argument, %i given",
+ else if(strcmp(line->Parts[0], "goto") == 0) {
+ if( line->nParts-1 != 1 ) {
+ Log_Warning("Config", "Configuration command 'goto' requires 1 arguments, %i given",
line->nParts-1);
- continue;
}
- Log("[CFG ] Starting '%s' as a new task", line->Parts[1]);
- Proc_Spawn(line->Parts[1]);
+ jmpTarget = line->Parts[1];
+
+ jumpToLabel:
+ for( j = 0; j < file->nLines; j ++ )
+ {
+ if(file->Lines[j].nParts == 0)
+ continue;
+ if(file->Lines[j].Parts[0][0] != ':')
+ continue;
+ if( strcmp(file->Lines[j].Parts[0]+1, jmpTarget) == 0)
+ break;
+ }
+ if( j == file->nLines )
+ Log_Warning("Config", "Unable to find label '%s'", jmpTarget);
+ else
+ i = j;
}
else {
- Warning("Unknown configuration command '%s' on line %i",
+ Log_Warning("Config", "Unknown configuration command '%s' on line %i",
line->Parts[0],
line->TrueLine
);
// Clean up after ourselves
for( i = 0; i < file->nLines; i++ ) {
if( file->Lines[i].nParts == 0 ) continue; // Skip blank
+ for( j = 0; j < file->Lines[i].nParts; j++ ) {
+ if(IsHeap(file->Lines[i].Parts[j]))
+ free(file->Lines[i].Parts[j]);
+ }
free( file->Lines[i].Parts );
}
free( file );
// Quoted
if( *ptr == '"' ) {
ptr ++;
+ ret->Lines[i].Parts[j] = ptr;
while( *ptr && !(*ptr == '"' && ptr[-1] == '\\') && *ptr != '\n' )
ptr++;
}
// === PROTOTYPES ===
void Threads_Init();
-void Threads_SetName(char *NewName);
+ int Threads_SetName(char *NewName);
char *Threads_GetName(int ID);
void Threads_SetTickets(int Num);
tThread *Threads_CloneTCB(Uint *Err, Uint Flags);
* \fn void Threads_SetName(char *NewName)
* \brief Sets the current thread's name
*/
-void Threads_SetName(char *NewName)
+int Threads_SetName(char *NewName)
{
tThread *cur = Proc_GetCurThread();
if( IsHeap(cur->ThreadName) )
free( cur->ThreadName );
cur->ThreadName = malloc(strlen(NewName)+1);
strcpy(cur->ThreadName, NewName);
+ return 0;
}
/**
tThread *cur = Proc_GetCurThread();
tThread *thread;
- Log("Proc_Sleep: %i going to sleep", cur->TID);
+ //Log_Log("Threads", "%i going to sleep", cur->TID);
// Acquire Spinlock
LOCK( &giThreadListLock );
{
case THREAD_STAT_ACTIVE: break;
case THREAD_STAT_SLEEPING:
+ //Log_Log("Threads", "Waking %i (%p) from sleeping", Thread->TID, Thread);
LOCK( &giThreadListLock );
prev = Threads_int_GetPrev(&gSleepingThreads, Thread);
prev->Next = Thread->Next; // Remove from sleeping queue
Thread->Next = gActiveThreads; // Add to active queue
gActiveThreads = Thread;
+ giNumActiveThreads ++;
+ giTotalTickets += Thread->NumTickets;
Thread->Status = THREAD_STAT_ACTIVE;
RELEASE( &giThreadListLock );
break;
}
}
+void Threads_WakeTID(tTID Thread)
+{
+ Threads_Wake( Threads_GetThread(Thread) );
+}
+
/**
* \fn void Threads_AddActive(tThread *Thread)
* \brief Adds a thread to the active queue
int ticket;
int number;
- if(giNumActiveThreads == 0) return NULL;
+ if(giNumActiveThreads == 0) {
+ //Log_Debug("Threads", "CPU%i has no threads to run", CPU);
+ return NULL;
+ }
// Special case: 1 thread
if(giNumActiveThreads == 1) {
+ //Log_Debug("Threads", "CPU%i has only one thread %i %s",
+ // CPU, gActiveThreads->TID, gActiveThreads->ThreadName);
return gActiveThreads;
}
giTotalTickets, number);
}
+ //Log_Debug("Threads", "Switching CPU%i to %p (%s)",
+ // CPU, thread, thread->ThreadName);
+
return thread;
}
#include <fs_devfs.h>
// === PROTOTYPES ===
- int DevFS_AddDevice(tDevFS_Driver *Dev);
+ int DevFS_AddDevice(tDevFS_Driver *Device);
+void DevFS_DelDevice(tDevFS_Driver *Device);
tVFS_Node *DevFS_InitDevice(char *Device, char **Options);
char *DevFS_ReadDir(tVFS_Node *Node, int Pos);
tVFS_Node *DevFS_FindDir(tVFS_Node *Node, char *Name);
};
tDevFS_Driver *gDevFS_Drivers = NULL;
int giDevFS_NextID = 1;
+tSpinlock glDevFS_ListLock;
// === CODE ===
/**
- * \fn int DevFS_AddDevice(tDevFS_Driver *Dev)
+ * \fn int DevFS_AddDevice(tDevFS_Driver *Device)
*/
-int DevFS_AddDevice(tDevFS_Driver *Dev)
+int DevFS_AddDevice(tDevFS_Driver *Device)
{
- Dev->Next = gDevFS_Drivers;
- gDevFS_Drivers = Dev;
- gDevFS_RootNode.Size ++;
- return giDevFS_NextID++;
+ int ret = 0;
+ tDevFS_Driver *dev;
+
+ LOCK( &glDevFS_ListLock );
+
+ // Check if the device is already registered or the name is taken
+ for( dev = gDevFS_Drivers; dev; dev = dev->Next )
+ {
+ if(dev == Device) break;
+ if(strcmp(dev->Name, Device->Name) == 0) break;
+ }
+
+ if(dev) {
+ if(dev == Device)
+ Log_Warning("DevFS", "Device %p '%s' attempted to register itself twice",
+ dev, dev->Name);
+ else
+ Log_Warning("DevFS", "Device %p attempted to register '%s' which was owned by %p",
+ Device, dev->Name, dev);
+ ret = 0; // Error
+ }
+ else {
+ Device->Next = gDevFS_Drivers;
+ gDevFS_Drivers = Device;
+ gDevFS_RootNode.Size ++;
+ ret = giDevFS_NextID ++;
+ }
+ RELEASE( &glDevFS_ListLock );
+
+ return ret;
+}
+
+/**
+ * \brief Delete a device from the DevFS folder
+ */
+void DevFS_DelDevice(tDevFS_Driver *Device)
+{
+ tDevFS_Driver *prev = NULL, *dev;
+
+ LOCK( &glDevFS_ListLock );
+ // Search list for device
+ for(dev = gDevFS_Drivers;
+ dev && dev != Device;
+ prev = dev, dev = dev->Next
+ );
+
+ // Check if it was found
+ if(dev)
+ {
+ if(prev)
+ prev->Next = Device->Next;
+ else
+ gDevFS_Drivers = Device->Next;
+ }
+ else
+ Log_Warning("DevFS", "Attempted to unregister device %p '%s' which was not registered",
+ Device, Device->Name);
+
+ RELEASE( &glDevFS_ListLock );
}
/**
dev = dev->Next
);
- return strdup(dev->Name);
+ if(dev)
+ return strdup(dev->Name);
+ else
+ return NULL;
}
/**
// --- EXPORTS ---
EXPORT(DevFS_AddDevice);
+EXPORT(DevFS_DelDevice);
+++ /dev/null
-/*\r
- * Acess 2\r
- * FAT12/16/32 Driver Version (Incl LFN)\r
- */\r
-#define DEBUG 0\r
-#define VERBOSE 1\r
-\r
-#define CACHE_FAT 1 //!< Caches the FAT in memory\r
-#define USE_LFN 1 //!< Enables the use of Long File Names\r
-\r
-#include <acess.h>\r
-#include <modules.h>\r
-#include <vfs.h>\r
-#include "fs_fat.h"\r
-\r
-\r
-// === TYPES ===\r
-#if USE_LFN\r
-typedef struct s_lfncache {\r
- Uint Inode, Impl;\r
- int id;\r
- char Name[256];\r
- struct s_lfncache *Next;\r
-} t_lfncache;\r
-#endif\r
-\r
-// === PROTOTYPES ===\r
- int FAT_Install(char **Arguments);\r
-tVFS_Node *FAT_InitDevice(char *device, char **options);\r
-void FAT_Unmount(tVFS_Node *Node);\r
-Uint64 FAT_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);\r
-Uint64 FAT_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);\r
-char *FAT_ReadDir(tVFS_Node *dirNode, int dirpos);\r
-tVFS_Node *FAT_FindDir(tVFS_Node *dirNode, char *file);\r
- int FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags);\r
- int FAT_Relink(tVFS_Node *node, char *OldName, char *NewName);\r
-void FAT_CloseFile(tVFS_Node *node);\r
-\r
-// === SEMI-GLOBALS ===\r
-MODULE_DEFINE(0, 0x51 /*v0.80*/, VFAT, FAT_Install, NULL, NULL);\r
-tFAT_VolInfo gFAT_Disks[8];\r
- int giFAT_PartCount = 0;\r
-#if USE_LFN\r
-t_lfncache *fat_lfncache;\r
-#endif\r
-tVFS_Driver gFAT_FSInfo = {\r
- "fat", 0, FAT_InitDevice, FAT_Unmount, NULL\r
- };\r
-\r
-// === CODE ===\r
-/**\r
- * \fn int FAT_Install(char **Arguments)\r
- * \brief \r
- */\r
-int FAT_Install(char **Arguments)\r
-{\r
- VFS_AddDriver( &gFAT_FSInfo );\r
- return MODULE_INIT_SUCCESS;\r
-}\r
-\r
-/**\r
- * \fn tVFS_Node *FAT_InitDevice(char *Device, char **options)\r
- * \brief Reads the boot sector of a disk and prepares the structures for it\r
- */\r
-tVFS_Node *FAT_InitDevice(char *Device, char **options)\r
-{\r
- fat_bootsect *bs;\r
- int i;\r
- Uint32 FATSz, RootDirSectors, TotSec, CountofClusters;\r
- tVFS_Node *node = NULL;\r
- tFAT_VolInfo *diskInfo = &gFAT_Disks[giFAT_PartCount];\r
- \r
- //Temporary Pointer\r
- bs = &diskInfo->bootsect;\r
- \r
- //Open device and read boot sector\r
- diskInfo->fileHandle = VFS_Open(Device, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE);\r
- if(diskInfo->fileHandle == -1) {\r
- Warning("FAT_InitDisk - Unable to open device '%s'", Device);\r
- return NULL;\r
- }\r
- \r
- VFS_ReadAt(diskInfo->fileHandle, 0, 512, bs);\r
- \r
- if(bs->bps == 0 || bs->spc == 0) {\r
- Warning("FAT_InitDisk - Error in FAT Boot Sector\n");\r
- return NULL;\r
- }\r
- \r
- //FAT Type Determining\r
- // From Microsoft FAT Specifcation\r
- RootDirSectors = ((bs->files_in_root*32) + (bs->bps - 1)) / bs->bps;\r
- \r
- if(bs->fatSz16 != 0) FATSz = bs->fatSz16;\r
- else FATSz = bs->spec.fat32.fatSz32;\r
- \r
- if(bs->totalSect16 != 0) TotSec = bs->totalSect16;\r
- else TotSec = bs->totalSect32;\r
- \r
- CountofClusters = (TotSec - (bs->resvSectCount + (bs->fatCount * FATSz) + RootDirSectors)) / bs->spc;\r
- \r
- if(CountofClusters < 4085)\r
- diskInfo->type = FAT12;\r
- else if(CountofClusters < 65525)\r
- diskInfo->type = FAT16;\r
- else\r
- diskInfo->type = FAT32;\r
- \r
- #if VERBOSE\r
- {\r
- char *sFatType, *sSize;\r
- Uint iSize = CountofClusters * bs->spc / 2;\r
- \r
- switch(diskInfo->type)\r
- {\r
- case FAT12: sFatType = "FAT12"; break;\r
- case FAT16: sFatType = "FAT16"; break;\r
- case FAT32: sFatType = "FAT32"; break;\r
- default: sFatType = "UNKNOWN"; break;\r
- }\r
- if(iSize <= 2*1024) {\r
- sSize = "KiB";\r
- }\r
- else if(iSize <= 2*1024*1024) {\r
- sSize = "MiB";\r
- iSize >>= 10;\r
- }\r
- else {\r
- sSize = "GiB";\r
- iSize >>= 20;\r
- }\r
- Log("[FAT ] '%s' %s, %i %s", Device, sFatType, iSize, sSize);\r
- }\r
- #endif\r
- \r
- //Get Name\r
- if(diskInfo->type == FAT32) {\r
- for(i=0;i<11;i++)\r
- diskInfo->name[i] = (bs->spec.fat32.label[i] == ' ' ? '\0' : bs->spec.fat32.label[i]);\r
- }\r
- else {\r
- for(i=0;i<11;i++)\r
- diskInfo->name[i] = (bs->spec.fat16.label[i] == ' ' ? '\0' : bs->spec.fat16.label[i]);\r
- }\r
- diskInfo->name[11] = '\0';\r
- \r
- //Compute Root directory offset\r
- if(diskInfo->type == FAT32)\r
- diskInfo->rootOffset = bs->spec.fat32.rootClust;\r
- else\r
- diskInfo->rootOffset = (FATSz * bs->fatCount) / bs->spc;\r
- \r
- diskInfo->clusterCount = CountofClusters;\r
- \r
- diskInfo->firstDataSect = bs->resvSectCount + (bs->fatCount * FATSz) + RootDirSectors;\r
- \r
- //Allow for Caching the FAT\r
- #if CACHE_FAT\r
- {\r
- Uint32 Ofs;\r
- diskInfo->FATCache = (Uint32*)malloc(sizeof(Uint32)*CountofClusters);\r
- if(diskInfo->FATCache == NULL) {\r
- Warning("FAT_InitDisk - Heap Exhausted\n");\r
- return NULL;\r
- }\r
- Ofs = bs->resvSectCount*512;\r
- if(diskInfo->type == FAT12) {\r
- Uint32 val;\r
- int j;\r
- char buf[1536];\r
- for(i=0;i<CountofClusters/2;i++) {\r
- j = i & 511; //%512\r
- if( j == 0 ) {\r
- VFS_ReadAt(diskInfo->fileHandle, Ofs, 3*512, buf);\r
- Ofs += 3*512;\r
- }\r
- val = *((int*)(buf+j*3));\r
- diskInfo->FATCache[i*2] = val & 0xFFF;\r
- diskInfo->FATCache[i*2+1] = (val>>12) & 0xFFF;\r
- }\r
- }\r
- if(diskInfo->type == FAT16) {\r
- Uint16 buf[256];\r
- for(i=0;i<CountofClusters;i++) {\r
- if( (i & 255) == 0 ) {\r
- VFS_ReadAt(diskInfo->fileHandle, Ofs, 512, buf);\r
- Ofs += 512;\r
- }\r
- diskInfo->FATCache[i] = buf[i&255];\r
- }\r
- }\r
- if(diskInfo->type == FAT32) {\r
- Uint32 buf[128];\r
- for(i=0;i<CountofClusters;i++) {\r
- if( (i & 127) == 0 ) {\r
- VFS_ReadAt(diskInfo->fileHandle, Ofs, 512, buf);\r
- Ofs += 512;\r
- }\r
- diskInfo->FATCache[i] = buf[i&127];\r
- }\r
- }\r
- LOG("FAT Fully Cached");\r
- }\r
- #endif /*CACHE_FAT*/\r
- \r
- //Initalise inode cache for FAT\r
- diskInfo->inodeHandle = Inode_GetHandle();\r
- LOG("Inode Cache handle is %i", diskInfo->inodeHandle);\r
- \r
- // == VFS Interface\r
- node = &diskInfo->rootNode;\r
- node->Inode = diskInfo->rootOffset;\r
- node->Size = bs->files_in_root; // Unknown - To be set on readdir\r
- node->ImplInt = giFAT_PartCount;\r
- \r
- node->ReferenceCount = 1;\r
- \r
- node->UID = 0; node->GID = 0;\r
- node->NumACLs = 1;\r
- node->ACLs = &gVFS_ACL_EveryoneRWX;\r
- node->Flags = VFS_FFLAG_DIRECTORY;\r
- node->CTime = node->MTime = node->ATime = now();\r
- \r
- node->Read = node->Write = NULL;\r
- node->ReadDir = FAT_ReadDir;\r
- node->FindDir = FAT_FindDir;\r
- node->Relink = FAT_Relink;\r
- node->MkNod = FAT_Mknod;\r
- //node->Close = FAT_CloseDevice;\r
- \r
- giFAT_PartCount ++;\r
- return node;\r
-}\r
-\r
-/**\r
- * \fn void FAT_Unmount(tVFS_Node *Node)\r
- * \brief Closes a mount and marks it as free\r
- */\r
-void FAT_Unmount(tVFS_Node *Node)\r
-{\r
- // Close Disk Handle\r
- VFS_Close( gFAT_Disks[Node->ImplInt].fileHandle );\r
- // Clear Node Cache\r
- Inode_ClearCache(gFAT_Disks[Node->ImplInt].inodeHandle);\r
- // Mark as unused\r
- gFAT_Disks[Node->ImplInt].fileHandle = -2;\r
- return;\r
-}\r
-\r
-/**\r
- * \fn static Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster)\r
- * \brief Fetches a value from the FAT\r
- */\r
-static Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster)\r
-{\r
- Uint32 val = 0;\r
- #if !CACHE_FAT\r
- Uint32 ofs = Disk->bootsect.resvSectCount*512;\r
- #endif\r
- ENTER("pDisk xCluster", Disk, cluster);\r
- #if CACHE_FAT\r
- val = Disk->FATCache[cluster];\r
- if(Disk->type == FAT12 && val == EOC_FAT12) val = -1;\r
- if(Disk->type == FAT16 && val == EOC_FAT16) val = -1;\r
- if(Disk->type == FAT32 && val == EOC_FAT32) val = -1;\r
- #else\r
- if(Disk->type == FAT12) {\r
- VFS_ReadAt(Disk->fileHandle, ofs+(cluster>>1)*3, 3, &val);\r
- val = (cluster&1 ? val&0xFFF : val>>12);\r
- if(val == EOC_FAT12) val = -1;\r
- } else if(Disk->type == FAT16) {\r
- VFS_ReadAt(Disk->fileHandle, ofs+cluster*2, 2, &val);\r
- if(val == EOC_FAT16) val = -1;\r
- } else {\r
- VFS_ReadAt(Disk->fileHandle, ofs+cluster*4, 4, &val);\r
- if(val == EOC_FAT32) val = -1;\r
- }\r
- #endif /*CACHE_FAT*/\r
- LEAVE('x', val);\r
- return val;\r
-}\r
-\r
-/* Reads a cluster's data\r
- */\r
-static void FAT_int_ReadCluster(int Handle, Uint32 Cluster, int Length, void *Buffer)\r
-{\r
- ENTER("iHandle xCluster iLength pBuffer", Handle, Cluster, Length, Buffer);\r
- //Log("Cluster = %i (0x%x)", Cluster, Cluster);\r
- VFS_ReadAt(\r
- gFAT_Disks[Handle].fileHandle,\r
- (gFAT_Disks[Handle].firstDataSect + (Cluster-2)*gFAT_Disks[Handle].bootsect.spc )\r
- * gFAT_Disks[Handle].bootsect.bps,\r
- Length,\r
- Buffer\r
- );\r
- LEAVE('-');\r
-}\r
-\r
-/**\r
- * \fn Uint64 FAT_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer)\r
- * \brief Reads data from a specified file\r
- */\r
-Uint64 FAT_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer)\r
-{\r
- int preSkip, count;\r
- int handle = node->ImplInt;\r
- int i, cluster, pos;\r
- int bpc;\r
- void *tmpBuf;\r
- tFAT_VolInfo *disk = &gFAT_Disks[node->ImplInt];\r
- \r
- ENTER("Xoffset Xlength pbuffer", offset, length, buffer);\r
- \r
- // Calculate and Allocate Bytes Per Cluster\r
- bpc = disk->bootsect.spc * disk->bootsect.bps;\r
- tmpBuf = (void*) malloc(bpc);\r
- LOG("malloc'd %i bytes", bpc);\r
- \r
- // Cluster is stored in Inode Field\r
- cluster = node->Inode;\r
- \r
- // Sanity Check offset\r
- if(offset > node->Size) {\r
- //LOG("Reading past EOF (%i > %i)", offset, node->Size);\r
- LEAVE('i', 0);\r
- return 0;\r
- }\r
- // Clamp Size\r
- if(offset + length > node->Size) {\r
- //LOG("Reading past EOF (%lli + %lli > %lli), clamped to %lli",\r
- // offset, length, node->Size, node->Size - offset);\r
- length = node->Size - offset;\r
- }\r
- \r
- // Single Cluster including offset\r
- if(length + offset < bpc)\r
- {\r
- FAT_int_ReadCluster(handle, cluster, bpc, tmpBuf);\r
- memcpy( buffer, (void*)( tmpBuf + offset%bpc ), length );\r
- free(tmpBuf);\r
- LEAVE('i', 1);\r
- return length;\r
- }\r
- \r
- preSkip = offset / bpc;\r
- \r
- //Skip previous clusters\r
- for(i=preSkip;i--;) {\r
- cluster = FAT_int_GetFatValue(disk, cluster);\r
- if(cluster == -1) {\r
- Warning("FAT_Read - Offset is past end of cluster chain mark");\r
- LEAVE('i', 0);\r
- return 0;\r
- }\r
- }\r
- \r
- // Get Count of Clusters to read\r
- count = ((offset%bpc+length) / bpc) + 1;\r
- \r
- // Get buffer Position after 1st cluster\r
- pos = bpc - offset%bpc;\r
- \r
- // Read 1st Cluster\r
- FAT_int_ReadCluster(handle, cluster, bpc, tmpBuf);\r
- memcpy(\r
- buffer,\r
- (void*)( tmpBuf + (bpc-pos) ),\r
- (pos < length ? pos : length)\r
- );\r
- \r
- if (count == 1) {\r
- free(tmpBuf);\r
- LEAVE('i', 1);\r
- return length;\r
- }\r
- \r
- cluster = FAT_int_GetFatValue(disk, cluster);\r
- \r
- #if DEBUG\r
- LOG("pos=%i\n", pos);\r
- LOG("Reading the rest of the clusters\n");\r
- #endif\r
- \r
- \r
- //Read the rest of the cluster data\r
- for( i = 1; i < count-1; i++ )\r
- {\r
- FAT_int_ReadCluster(handle, cluster, bpc, tmpBuf);\r
- memcpy((void*)(buffer+pos), tmpBuf, bpc);\r
- pos += bpc;\r
- cluster = FAT_int_GetFatValue(disk, cluster);\r
- if(cluster == -1) {\r
- Warning("FAT_Read - Read past End of Cluster Chain");\r
- free(tmpBuf);\r
- LEAVE('i', 0);\r
- return 0;\r
- }\r
- }\r
- \r
- FAT_int_ReadCluster(handle, cluster, bpc, tmpBuf);\r
- memcpy((void*)(buffer+pos), tmpBuf, length-pos);\r
- \r
- #if DEBUG\r
- LOG("Free tmpBuf(0x%x) and Return\n", tmpBuf);\r
- #endif\r
- \r
- free(tmpBuf);\r
- LEAVE('X', length);\r
- return length;\r
-}\r
-\r
-/**\r
- * \fn Uint64 FAT_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer)\r
- */\r
-Uint64 FAT_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer)\r
-{\r
- return 0;\r
-}\r
-\r
-/**\r
- * \fn static void FAT_int_ProperFilename(char *dest, char *src)\r
- * \brief Converts a FAT directory entry name into a proper filename\r
- */\r
-static void FAT_int_ProperFilename(char *dest, char *src)\r
-{\r
- int a, b;\r
- \r
- for( a = 0; a < 8; a++) {\r
- if(src[a] == ' ') break;\r
- dest[a] = src[a];\r
- }\r
- b = a;\r
- a = 8;\r
- if(src[8] != ' ')\r
- dest[b++] = '.';\r
- for( ; a < 11; a++, b++) {\r
- if(src[a] == ' ') break;\r
- dest[b] = src[a];\r
- }\r
- dest[b] = '\0';\r
- #if DEBUG\r
- //Log("FAT_int_ProperFilename: dest='%s'", dest);\r
- #endif\r
-}\r
-\r
-/**\r
- * \fn char *FAT_int_CreateName(tVFS_Node *parent, fat_filetable *ft, char *LongFileName)\r
- * \brief Converts either a LFN or a 8.3 Name into a proper name\r
- */\r
-char *FAT_int_CreateName(tVFS_Node *parent, fat_filetable *ft, char *LongFileName)\r
-{\r
- char *ret;\r
- int len;\r
- #if USE_LFN\r
- if(LongFileName && LongFileName[0] != '\0')\r
- { \r
- len = strlen(LongFileName);\r
- ret = malloc(len+1);\r
- strcpy(ret, LongFileName);\r
- }\r
- else\r
- {\r
- #endif\r
- ret = (char*) malloc(13);\r
- memset(ret, 13, '\0');\r
- FAT_int_ProperFilename(ret, ft->name);\r
- #if USE_LFN\r
- }\r
- #endif\r
- return ret;\r
-}\r
-\r
-/**\r
- * \fn tVFS_Node *FAT_int_CreateNode(tVFS_Node *parent, fat_filetable *ft, char *LongFileName)\r
- * \brief Creates a tVFS_Node structure for a given file entry\r
- */\r
-tVFS_Node *FAT_int_CreateNode(tVFS_Node *parent, fat_filetable *ft, char *LongFileName)\r
-{\r
- tVFS_Node node = {0};\r
- tVFS_Node *ret;\r
- \r
- ENTER("pParent pFT sLongFileName", parent, ft, LongFileName);\r
- \r
- // Set Other Data\r
- node.Inode = ft->cluster | (ft->clusterHi<<16);\r
- node.Size = ft->size;\r
- LOG("ft->size = %i", ft->size);\r
- node.ImplInt = parent->ImplInt;\r
- node.UID = 0; node.GID = 0;\r
- node.NumACLs = 1;\r
- node.ACLs = &gVFS_ACL_EveryoneRWX; // RWXRWXRWX\r
- \r
- node.Flags = 0;\r
- if(ft->attrib & ATTR_DIRECTORY) node.Flags |= VFS_FFLAG_DIRECTORY;\r
- if(ft->attrib & ATTR_READONLY) node.Flags |= VFS_FFLAG_READONLY;\r
- \r
- node.ATime = timestamp(0,0,0,\r
- ((ft->adate&0x1F)-1), //Days\r
- ((ft->adate&0x1E0)-1), //Months\r
- 1980+((ft->adate&0xFF00)>>8)); //Years\r
- \r
- node.CTime = ft->ctimems * 10; //Miliseconds\r
- node.CTime += timestamp(\r
- (ft->ctime&0x1F)<<1, //Seconds\r
- ((ft->ctime&0x3F0)>>5), //Minutes\r
- ((ft->ctime&0xF800)>>11), //Hours\r
- ((ft->cdate&0x1F)-1), //Days\r
- ((ft->cdate&0x1E0)-1), //Months\r
- 1980+((ft->cdate&0xFF00)>>8)); //Years\r
- \r
- node.MTime = timestamp(\r
- (ft->mtime&0x1F)<<1, //Seconds\r
- ((ft->mtime&0x3F0)>>5), //Minuites\r
- ((ft->mtime&0xF800)>>11), //Hours\r
- ((ft->mdate&0x1F)-1), //Days\r
- ((ft->mdate&0x1E0)-1), //Months\r
- 1980+((ft->mdate&0xFF00)>>8)); //Years\r
- \r
- if(node.Flags & VFS_FFLAG_DIRECTORY) {\r
- node.ReadDir = FAT_ReadDir;\r
- node.FindDir = FAT_FindDir;\r
- node.MkNod = FAT_Mknod;\r
- node.Size = -1;\r
- } else {\r
- node.Read = FAT_Read;\r
- node.Write = FAT_Write;\r
- }\r
- node.Close = FAT_CloseFile;\r
- node.Relink = FAT_Relink;\r
- \r
- ret = Inode_CacheNode(gFAT_Disks[parent->ImplInt].inodeHandle, &node);\r
- LEAVE('p', ret);\r
- return ret;\r
-}\r
-\r
-#if USE_LFN\r
-/**\r
- \fn char *FAT_int_GetLFN(tVFS_Node *node)\r
- \brief Return pointer to LFN cache entry\r
- */\r
-char *FAT_int_GetLFN(tVFS_Node *node)\r
-{\r
- t_lfncache *tmp;\r
- tmp = fat_lfncache;\r
- while(tmp)\r
- {\r
- if(tmp->Inode == node->Inode && tmp->Impl == node->ImplInt)\r
- return tmp->Name;\r
- tmp = tmp->Next;\r
- }\r
- tmp = malloc(sizeof(t_lfncache));\r
- tmp->Inode = node->Inode;\r
- tmp->Impl = node->ImplInt;\r
- memset(tmp->Name, 0, 256);\r
- \r
- tmp->Next = fat_lfncache;\r
- fat_lfncache = tmp;\r
- \r
- return tmp->Name;\r
-}\r
-\r
-/**\r
- \fn void FAT_int_DelLFN(tVFS_Node *node)\r
- \brief Delete a LFN cache entry\r
-*/\r
-void FAT_int_DelLFN(tVFS_Node *node)\r
-{\r
- t_lfncache *tmp;\r
- \r
- if(!fat_lfncache) return;\r
- \r
- if(!fat_lfncache->Next)\r
- {\r
- tmp = fat_lfncache;\r
- fat_lfncache = tmp->Next;\r
- free(tmp);\r
- return;\r
- }\r
- tmp = fat_lfncache;\r
- while(tmp && tmp->Next)\r
- {\r
- if(tmp->Inode == node->Inode && tmp->Impl == node->ImplInt)\r
- {\r
- free(tmp->Next);\r
- tmp->Next = tmp->Next->Next;\r
- return;\r
- }\r
- tmp = tmp->Next;\r
- }\r
-}\r
-#endif\r
-\r
-/**\r
- \fn char *FAT_ReadDir(tVFS_Node *dirNode, int dirPos)\r
- \param dirNode Node structure of directory\r
- \param dirPos Directory position\r
-**/\r
-char *FAT_ReadDir(tVFS_Node *dirNode, int dirpos)\r
-{\r
- fat_filetable fileinfo[16]; //Sizeof=32, 16 per sector\r
- int a=0;\r
- tFAT_VolInfo *disk = &gFAT_Disks[dirNode->ImplInt&7];\r
- Uint32 cluster, offset;\r
- int preSkip;\r
- char *ret;\r
- #if USE_LFN\r
- char *lfn = NULL;\r
- #endif\r
- \r
- ENTER("pDirNode iDirPos", dirNode, dirpos);\r
- \r
- // Get Byte Offset and skip\r
- offset = dirpos * sizeof(fat_filetable);\r
- preSkip = offset / (512 * disk->bootsect.spc);\r
- LOG("disk->bootsect.spc = %i", disk->bootsect.spc);\r
- LOG("dirNode->size = %i", dirNode->Size);\r
- cluster = dirNode->Inode; // Cluster ID\r
- \r
- // Do Cluster Skip\r
- // - Pre FAT32 had a reserved area for the root.\r
- if( disk->type == FAT32 || cluster != disk->rootOffset )\r
- {\r
- //Skip previous clusters\r
- for(a=preSkip;a--;) {\r
- cluster = FAT_int_GetFatValue(disk, cluster);\r
- // Check for end of cluster chain\r
- if(cluster == -1) { LEAVE('n'); return NULL;}\r
- }\r
- }\r
- \r
- // Bounds Checking (Used to spot heap overflows)\r
- if(cluster > disk->clusterCount + 2)\r
- {\r
- Warning("FAT_ReadDir - Cluster ID is over cluster count (0x%x>0x%x)",\r
- cluster, disk->clusterCount+2);\r
- LEAVE('n');\r
- return NULL;\r
- }\r
- \r
- LOG("cluster=0x%x, dirpos=%i", cluster, dirpos);\r
- \r
- // Compute Offsets\r
- // - Pre FAT32 cluster base (in sectors)\r
- if( cluster == disk->rootOffset && disk->type != FAT32 )\r
- offset = disk->bootsect.resvSectCount + cluster*disk->bootsect.spc;\r
- else\r
- { // FAT32 cluster base (in sectors)\r
- offset = disk->firstDataSect;\r
- offset += (cluster - 2) * disk->bootsect.spc;\r
- }\r
- // Sector in cluster\r
- if(disk->bootsect.spc != 1)\r
- offset += (dirpos / 16) % disk->bootsect.spc;\r
- // Offset in sector\r
- a = dirpos % 16;\r
-\r
- LOG("offset=%i, a=%i", offset, a);\r
- \r
- // Read Sector\r
- VFS_ReadAt(disk->fileHandle, offset*512, 512, fileinfo); // Read Dir Data\r
- \r
- LOG("name[0] = 0x%x", (Uint8)fileinfo[a].name[0]);\r
- //Check if this is the last entry\r
- if( fileinfo[a].name[0] == '\0' ) {\r
- dirNode->Size = dirpos;\r
- LOG("End of list");\r
- LEAVE('n');\r
- return NULL; // break\r
- }\r
- \r
- // Check for empty entry\r
- if( (Uint8)fileinfo[a].name[0] == 0xE5 ) {\r
- LOG("Empty Entry");\r
- LEAVE('p', VFS_SKIP);\r
- return VFS_SKIP; // Skip\r
- }\r
- \r
- #if USE_LFN\r
- // Get Long File Name Cache\r
- lfn = FAT_int_GetLFN(dirNode);\r
- if(fileinfo[a].attrib == ATTR_LFN)\r
- {\r
- fat_longfilename *lfnInfo;\r
- int len;\r
- \r
- lfnInfo = (fat_longfilename *) &fileinfo[a];\r
- if(lfnInfo->id & 0x40) memset(lfn, 0, 256);\r
- // Get the current length\r
- len = strlen(lfn);\r
- \r
- // Sanity Check (FAT implementations should not allow >255 bytes)\r
- if(len + 13 > 255) return VFS_SKIP;\r
- // Rebase all bytes\r
- for(a=len+1;a--;) lfn[a+13] = lfn[a];\r
- \r
- // Append new bytes\r
- lfn[ 0] = lfnInfo->name1[0]; lfn[ 1] = lfnInfo->name1[1];\r
- lfn[ 2] = lfnInfo->name1[2]; lfn[ 3] = lfnInfo->name1[3];\r
- lfn[ 4] = lfnInfo->name1[4]; \r
- lfn[ 5] = lfnInfo->name2[0]; lfn[ 6] = lfnInfo->name2[1];\r
- lfn[ 7] = lfnInfo->name2[2]; lfn[ 8] = lfnInfo->name2[3];\r
- lfn[ 9] = lfnInfo->name2[4]; lfn[10] = lfnInfo->name2[5];\r
- lfn[11] = lfnInfo->name3[0]; lfn[12] = lfnInfo->name3[1];\r
- LEAVE('p', VFS_SKIP);\r
- return VFS_SKIP;\r
- }\r
- #endif\r
- \r
- //Check if it is a volume entry\r
- if(fileinfo[a].attrib & 0x08) {\r
- LEAVE('p', VFS_SKIP);\r
- return VFS_SKIP;\r
- }\r
- // Ignore . and ..\r
- if(fileinfo[a].name[0] == '.') {\r
- LEAVE('p', VFS_SKIP);\r
- return VFS_SKIP;\r
- } \r
- \r
- LOG("name='%c%c%c%c%c%c%c%c.%c%c%c'\n",\r
- fileinfo[a].name[0], fileinfo[a].name[1], fileinfo[a].name[2], fileinfo[a].name[3],\r
- fileinfo[a].name[4], fileinfo[a].name[5], fileinfo[a].name[6], fileinfo[a].name[7],\r
- fileinfo[a].name[8], fileinfo[a].name[9], fileinfo[a].name[10] );\r
- \r
- #if USE_LFN\r
- //node = FAT_int_CreateNode(dirNode, &fileinfo[a], lfn);\r
- ret = FAT_int_CreateName(dirNode, &fileinfo[a], lfn);\r
- lfn[0] = '\0';\r
- #else\r
- //node = FAT_int_CreateNode(dirNode, &fileinfo[a], NULL);\r
- ret = FAT_int_CreateName(dirNode, &fileinfo[a], NULL);\r
- #endif\r
- \r
- LEAVE('s', ret);\r
- return ret;\r
-}\r
-\r
-/**\r
- * \fn tVFS_Node *FAT_FindDir(tVFS_Node *node, char *name)\r
- * \brief Finds an entry in the current directory\r
- */\r
-tVFS_Node *FAT_FindDir(tVFS_Node *node, char *name)\r
-{\r
- fat_filetable fileinfo[16];\r
- char tmpName[11];\r
- #if USE_LFN\r
- fat_longfilename *lfnInfo;\r
- char *lfn = NULL;\r
- int lfnPos=255, lfnId = -1;\r
- #endif\r
- int i=0;\r
- tVFS_Node *tmpNode;\r
- Uint64 diskOffset;\r
- tFAT_VolInfo *disk = &gFAT_Disks[node->ImplInt];\r
- Uint32 dirCluster;\r
- Uint32 cluster;\r
- \r
- ENTER("pnode sname", node, name);\r
- \r
- // Fast Returns\r
- if(!name || name[0] == '\0') {\r
- LEAVE('n');\r
- return NULL;\r
- }\r
- \r
- #if USE_LFN\r
- lfn = FAT_int_GetLFN(node);\r
- #endif\r
- \r
- dirCluster = node->Inode;\r
- // Seek to Directory\r
- if( dirCluster == disk->rootOffset && disk->type != FAT32 )\r
- diskOffset = (disk->bootsect.resvSectCount+dirCluster*disk->bootsect.spc) << 9;\r
- else\r
- diskOffset = (disk->firstDataSect+(dirCluster-2)*disk->bootsect.spc) << 9;\r
- \r
- for(;;i++)\r
- {\r
- // Load sector\r
- if((i & 0xF) == 0) {\r
- //Log("FAT_FindDir: diskOffset = 0x%x", diskOffset);\r
- VFS_ReadAt(disk->fileHandle, diskOffset, 512, fileinfo);\r
- diskOffset += 512;\r
- }\r
- \r
- //Check if the files are free\r
- if(fileinfo[i&0xF].name[0] == '\0') break; //Free and last\r
- if(fileinfo[i&0xF].name[0] == '\xE5') goto loadCluster; //Free\r
- \r
- \r
- #if USE_LFN\r
- // Long File Name Entry\r
- if(fileinfo[i&0xF].attrib == ATTR_LFN)\r
- {\r
- lfnInfo = (fat_longfilename *) &fileinfo[i&0xF];\r
- if(lfnInfo->id & 0x40) {\r
- memset(lfn, 0, 256);\r
- lfnPos = 255;\r
- }\r
- lfn[lfnPos--] = lfnInfo->name3[1]; lfn[lfnPos--] = lfnInfo->name3[0];\r
- lfn[lfnPos--] = lfnInfo->name2[5]; lfn[lfnPos--] = lfnInfo->name2[4];\r
- lfn[lfnPos--] = lfnInfo->name2[3]; lfn[lfnPos--] = lfnInfo->name2[2];\r
- lfn[lfnPos--] = lfnInfo->name2[1]; lfn[lfnPos--] = lfnInfo->name2[0];\r
- lfn[lfnPos--] = lfnInfo->name1[4]; lfn[lfnPos--] = lfnInfo->name1[3];\r
- lfn[lfnPos--] = lfnInfo->name1[2]; lfn[lfnPos--] = lfnInfo->name1[1];\r
- lfn[lfnPos--] = lfnInfo->name1[0];\r
- if((lfnInfo->id&0x3F) == 1)\r
- {\r
- memcpy(lfn, lfn+lfnPos+1, 256-lfnPos);\r
- lfnId = i+1;\r
- }\r
- }\r
- else\r
- {\r
- // Remove LFN if it does not apply\r
- if(lfnId != i) lfn[0] = '\0';\r
- #endif\r
- // Get Real Filename\r
- FAT_int_ProperFilename(tmpName, fileinfo[i&0xF].name);\r
- \r
- LOG("tmpName = '%s'", tmpName);\r
- \r
- //Only Long name is case sensitive, 8.3 is not\r
- #if USE_LFN\r
- if(strucmp(tmpName, name) == 0 || strcmp(lfn, name) == 0) {\r
- #else\r
- if(strucmp(tmpName, name) == 0) {\r
- #endif\r
- cluster = fileinfo[i&0xF].cluster | (fileinfo[i&0xF].clusterHi << 16);\r
- tmpNode = Inode_GetCache(disk->inodeHandle, cluster);\r
- if(tmpNode == NULL) // Node is not cached\r
- {\r
- #if USE_LFN\r
- tmpNode = FAT_int_CreateNode(node, &fileinfo[i&0xF], lfn);\r
- #else\r
- tmpNode = FAT_int_CreateNode(node, &fileinfo[i&0xF], NULL);\r
- #endif\r
- }\r
- #if USE_LFN\r
- lfn[0] = '\0';\r
- #endif\r
- LEAVE('p', tmpNode);\r
- return tmpNode;\r
- }\r
- #if USE_LFN\r
- }\r
- #endif\r
- \r
- loadCluster:\r
- //Load Next cluster?\r
- if( ((i+1) >> 4) % disk->bootsect.spc == 0 && ((i+1) & 0xF) == 0)\r
- {\r
- if( dirCluster == disk->rootOffset && disk->type != FAT32 )\r
- continue;\r
- dirCluster = FAT_int_GetFatValue(disk, dirCluster);\r
- if(dirCluster == -1) break;\r
- diskOffset = (disk->firstDataSect+(dirCluster-2)*disk->bootsect.spc)*512;\r
- }\r
- }\r
- \r
- LEAVE('n');\r
- return NULL;\r
-}\r
-\r
-/**\r
- * \fn int FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags)\r
- * \brief Create a new node\r
- */\r
-int FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags)\r
-{\r
- return 0;\r
-}\r
-\r
-/**\r
- * \fn int FAT_Relink(tVFS_Node *Node, char *OldName, char *NewName)\r
- * \brief Rename / Delete a file\r
- */\r
-int FAT_Relink(tVFS_Node *Node, char *OldName, char *NewName)\r
-{\r
- return 0;\r
-}\r
-\r
-/**\r
- * \fn void FAT_CloseFile(tVFS_Node *Node)\r
- * \brief Close an open file\r
- */\r
-void FAT_CloseFile(tVFS_Node *Node)\r
-{\r
- if(Node == NULL) return ;\r
- \r
- Inode_UncacheNode(gFAT_Disks[Node->ImplInt].inodeHandle, Node->Inode);\r
- #if USE_LFN\r
- if( !Inode_GetCache(gFAT_Disks[Node->ImplInt].inodeHandle, Node->Inode)\r
- && Node->Flags & VFS_FFLAG_DIRECTORY)\r
- FAT_int_DelLFN(Node);\r
- else // Get Cache references the node, so dereference it\r
- Inode_UncacheNode(gFAT_Disks[Node->ImplInt].inodeHandle, Node->Inode);\r
- #endif\r
- return ;\r
-}\r
-\r
-/**\r
- * \fn void fat_install()\r
- * \brief Add the FAT Filesystem to the VFS\r
- */\r
-void fat_install()\r
-{\r
- VFS_AddDriver( &gFAT_FSInfo );\r
-}\r
+++ /dev/null
-/*\r
- * Acess2\r
- * FAT12/16/32 Driver\r
- * vfs/fs/fs_fat.h\r
- */\r
-#ifndef _FS_FAT_H_\r
-#define _FS_FAT_H_\r
-\r
-// === On Disk Structures ===\r
-/**\r
- * \struct fat_bootsect_s\r
- * \brief Bootsector format\r
- */\r
-struct fat_bootsect_s\r
-{\r
- Uint8 jmp[3]; //!< Jump Instruction\r
- char oemname[8]; //!< OEM Name. Typically MSDOS1.1\r
- Uint16 bps; //!< Bytes per Sector. Assumed to be 512\r
- Uint8 spc; //!< Sectors per Cluster\r
- Uint16 resvSectCount; //!< Number of reserved sectors at beginning of volume\r
- Uint8 fatCount; //!< Number of copies of the FAT\r
- Uint16 files_in_root; //!< Count of files in the root directory\r
- Uint16 totalSect16; //!< Total sector count (FAT12/16)\r
- Uint8 mediaDesc; //!< Media Desctiptor\r
- Uint16 fatSz16; //!< FAT Size (FAT12/16)\r
- Uint16 spt; //!< Sectors per track. Ignored (Acess uses LBA)\r
- Uint16 heads; //!< Heads. Ignored (Acess uses LBA)\r
- Uint32 hiddenCount; //!< ???\r
- Uint32 totalSect32; //!< Total sector count (FAT32)\r
- union {\r
- struct {\r
- Uint8 drvNum; //!< Drive Number. BIOS Drive ID (E.g. 0x80)\r
- Uint8 resv; //!< Reserved byte\r
- Uint8 bootSig; //!< Boot Signature. ???\r
- Uint32 volId; //!< Volume ID\r
- char label[11]; //!< Disk Label\r
- char fsType[8]; //!< FS Type. ???\r
- } __attribute__((packed)) fat16; //!< FAT16 Specific information\r
- struct {\r
- Uint32 fatSz32; //!< 32-Bit FAT Size\r
- Uint16 extFlags; //!< Extended flags\r
- Uint16 fsVer; //!< Filesystem Version\r
- Uint32 rootClust; //!< Root Cluster ID\r
- Uint16 fsInfo; //!< FS Info. ???\r
- Uint16 backupBS; //!< Backup Bootsector Sector Offset\r
- char resv[12]; //!< Reserved Data\r
- Uint8 drvNum; //!< Drive Number\r
- char resv2; //!< Reserved Data\r
- Uint8 bootSig; //!< Boot Signature. ???\r
- Uint32 volId; //!< Volume ID\r
- char label[11]; //!< Disk Label\r
- char fsType[8]; //!< Filesystem Type. ???\r
- } __attribute__((packed)) fat32; //!< FAT32 Specific Information\r
- }__attribute__((packed)) spec; //!< Non Shared Data\r
- char pad[512-90]; //!< Bootsector Data (Code/Boot Signature 0xAA55)\r
-} __attribute__((packed));\r
-\r
-/**\r
- \struct fat_filetable_s\r
- \brief Format of a 8.3 file entry on disk\r
-*/\r
-struct fat_filetable_s {\r
- char name[11]; //!< 8.3 Name\r
- Uint8 attrib; //!< File Attributes.\r
- Uint8 ntres; //!< Reserved for NT - Set to 0\r
- Uint8 ctimems; //!< 10ths of a second ranging from 0-199 (2 seconds)\r
- Uint16 ctime; //!< Creation Time\r
- Uint16 cdate; //!< Creation Date\r
- Uint16 adate; //!< Accessed Data. No Time feild though\r
- Uint16 clusterHi; //!< High Cluster. 0 for FAT12 and FAT16\r
- Uint16 mtime; //!< Last Modified Time\r
- Uint16 mdate; //!< Last Modified Date\r
- Uint16 cluster; //!< Low Word of First cluster\r
- Uint32 size; //!< Size of file\r
-} __attribute__((packed));\r
-\r
-/**\r
- \struct fat_longfilename_s\r
- \brief Format of a long file name entry on disk\r
-*/\r
-struct fat_longfilename_s {\r
- Uint8 id; //!< ID of entry. Bit 6 is set for last entry\r
- Uint16 name1[5]; //!< 5 characters of name\r
- Uint8 attrib; //!< Attributes. Must be ATTR_LFN\r
- Uint8 type; //!< Type. ???\r
- Uint8 checksum; //!< Checksum\r
- Uint16 name2[6]; //!< 6 characters of name\r
- Uint16 firstCluster; //!< Used for non LFN compatability. Set to 0\r
- Uint16 name3[2]; //!< Last 2 characters of name\r
-} __attribute__((packed));\r
-\r
-/**\r
- * \name File Attributes\r
- * \brief Flag values for ::fat_filetable_s.attrib\r
- * \{\r
- */\r
-#define ATTR_READONLY 0x01 //!< Read-only file\r
-#define ATTR_HIDDEN 0x02 //!< Hidden File\r
-#define ATTR_SYSTEM 0x04 //!< System File\r
-#define ATTR_VOLUMEID 0x08 //!< Volume ID (Deprecated)\r
-#define ATTR_DIRECTORY 0x10 //!< Directory\r
-/**\r
- * \brief File needs archiving\r
- * \note User set flag, no significance to the FS driver\r
- */\r
-#define ATTR_ARCHIVE 0x20\r
-/**\r
- * \brief Meta Attribute \r
- * \r
- * If ::fat_filetable_s.attrib equals ATTR_LFN the file is a LFN entry\r
- */\r
-#define ATTR_LFN (ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUMEID)\r
-/**\r
- * \}\r
- */\r
-\r
-/**\r
- * \brief Internal IDs for FAT types\r
- */\r
-enum eFatType\r
-{\r
- FAT12, //!< FAT12 Volume\r
- FAT16, //!< FAT16 Volume\r
- FAT32, //!< FAT32 Volume\r
-};\r
-\r
-/**\r
- * \name End of Cluster marks\r
- * \brief FAT values that indicate the end of a cluster chain in\r
- * different versions.\r
- * \{\r
- */\r
-#define EOC_FAT12 0x0FFF //!< FAT-12 Mark\r
-#define EOC_FAT16 0xFFFF //!< FAT-16 Mark\r
-#define EOC_FAT32 0x0FFFFFF //!< FAT-32 Mark\r
-/**\r
- * \}\r
- */\r
-\r
-typedef struct fat_bootsect_s fat_bootsect;\r
-typedef struct fat_filetable_s fat_filetable;\r
-typedef struct fat_longfilename_s fat_longfilename;\r
-\r
-// === Memory Structures ===\r
-/**\r
- * \struct drv_fat_volinfo_s\r
- * \brief Representation of a volume in memory\r
- */\r
-struct drv_fat_volinfo_s\r
-{\r
- int fileHandle; //!< File Handle\r
- int type; //!< FAT Type. See eFatType\r
- char name[12]; //!< Volume Name (With NULL Terminator)\r
- Uint32 firstDataSect; //!< First data sector\r
- Uint32 rootOffset; //!< Root Offset (clusters)\r
- Uint32 clusterCount; //!< Total Cluster Count\r
- fat_bootsect bootsect; //!< Boot Sector\r
- tVFS_Node rootNode; //!< Root Node\r
- int inodeHandle; //!< Inode Cache Handle\r
- #if CACHE_FAT\r
- Uint32 *FATCache; //!< FAT Cache\r
- #endif\r
-};\r
-\r
-typedef struct drv_fat_volinfo_s tFAT_VolInfo;\r
-\r
-#endif\r
int VFS_AddDriver(tVFS_Driver *Info);
void VFS_UpdateDriverFile();
+// === EXPORTS ===
+EXPORT(VFS_AddDriver);
+
// === GLOBALS ===
tVFS_Node NULLNode = {0};
tSpinlock siDriverListLock = 0;
*/
void VFS_GetMemPath(char *Dest, void *Base, Uint Length)
{
- Log("VFS_GetMemPath: (Base=%p, Length=0x%x, Dest=%p)", Base, Length, Dest);
Dest[0] = '$';
itoa( &Dest[1], (Uint)Base, 16, BITS/4, '0' );
Dest[BITS/4+1] = ':';
itoa( &Dest[BITS/4+2], Length, 16, BITS/4, '0' );
-
- Log("VFS_GetMemPath: Dest = \"%s\"", Dest);
+ Dest[BITS/2+2] = '\0';
}
/**
// Check for NULL byte
if(*str != '\0') return NULL;
- Log(" VFS_MemFile_Create: base=0x%x, size=0x%x", base, size);
-
// Allocate and fill node
ret = malloc(sizeof(tVFS_Node));
memset(ret, 0, sizeof(tVFS_Node));
// Get the filesystem
fs = VFS_GetFSByName(Filesystem);
if(!fs) {
- Warning("VFS_Mount - Unknown FS Type '%s'", Filesystem);
+ Log_Warning("VFS", "VFS_Mount - Unknown FS Type '%s'", Filesystem);
return -1;
}
}
RELEASE( &glVFS_MountList );
- Log("VFS_Mount: Mounted '%s' to '%s' ('%s')", Device, MountPoint, Filesystem);
+ Log_Log("VFS", "Mounted '%s' to '%s' ('%s')", Device, MountPoint, Filesystem);
VFS_UpdateMountFile();
tCachedInode *ent, *prev;
cache = Inode_int_GetFSCache(Handle);
- if(!cache) return;
+ if(!cache) return ;
- if(Inode > cache->MaxCached) return;
+ if(Inode > cache->MaxCached) return ;
// Search Cache
ent = cache->FirstNode;
free(ent);
}
- return;
+ return ;
}
+
+ return ;
}
/**
SUBMAKE = $(MAKE) --no-print-directory
MODULES += $(DYNMODS)
-USRLIBS = crt0.o acess.ld ld-acess.so libacess.so libgcc.so libc.so
-USRAPPS = init login CLIShell cat ls mount ifconfig
+USRLIBS := crt0.o acess.ld ld-acess.so libacess.so libgcc.so libc.so
+USRAPPS := init login CLIShell cat ls mount ifconfig
-ALL_MODULES = $(addprefix all-,$(MODULES))
-ALL_USRLIBS = $(addprefix all-,$(USRLIBS))
-ALL_USRAPPS = $(addprefix all-,$(USRAPPS))
-CLEAN_MODULES = $(addprefix clean-,$(MODULES))
-CLEAN_USRLIBS = $(addprefix clean-,$(USRLIBS))
-CLEAN_USRAPPS = $(addprefix clean-,$(USRAPPS))
-INSTALL_MODULES = $(addprefix install-,$(MODULES))
-INSTALL_USRLIBS = $(addprefix install-,$(USRLIBS))
-INSTALL_USRAPPS = $(addprefix install-,$(USRAPPS))
-ALLINSTALL_MODULES = $(addprefix allinstall-,$(MODULES))
-ALLINSTALL_USRLIBS = $(addprefix allinstall-,$(USRLIBS))
-ALLINSTALL_USRAPPS = $(addprefix allinstall-,$(USRAPPS))
+#ALL_DYNMODS = $(addprefix all-,$(DYNMODS))
+ALL_MODULES := $(addprefix all-,$(MODULES))
+ALL_USRLIBS := $(addprefix all-,$(USRLIBS))
+ALL_USRAPPS := $(addprefix all-,$(USRAPPS))
+CLEAN_MODULES := $(addprefix clean-,$(MODULES))
+CLEAN_USRLIBS := $(addprefix clean-,$(USRLIBS))
+CLEAN_USRAPPS := $(addprefix clean-,$(USRAPPS))
+INSTALL_MODULES := $(addprefix install-,$(MODULES))
+INSTALL_USRLIBS := $(addprefix install-,$(USRLIBS))
+INSTALL_USRAPPS := $(addprefix install-,$(USRAPPS))
+AI_DYNMODS := $(addprefix allinstall-,$(DYNMODS))
+AI_MODULES := $(addprefix allinstall-,$(MODULES))
+AI_USRLIBS := $(addprefix allinstall-,$(USRLIBS))
+AI_USRAPPS := $(addprefix allinstall-,$(USRAPPS))
.PHONY: all clean install \
$(ALL_MODULES) all-Kernel $(ALL_USRLIBS) $(ALL_USRAPPS) \
- $(ALLINSTALL_MODULES) allinstall-Kernel $(ALLINSTALL_USRLIBS) $(ALLINSTALL_USRAPPS) \
+ $(AI_MODULES) allinstall-Kernel $(AI_USRLIBS) $(AI_USRAPPS) \
$(CLEAN_MODULES) clean-Kernel $(CLEAN_USRLIBS) $(CLEAN_USRAPPS) \
$(INSTALL_MODULES) install-Kernel $(INSTALL_USRLIBS) $(INSTALL_USRAPPS)
-kmode: $(ALLINSTALL_MODULES) allinstall-Kernel
+kmode: $(AI_MODULES) $(AI_DYNMODS) allinstall-Kernel
-all: $(ALL_MODULES) all-Kernel $(ALL_USRLIBS) $(ALL_USRAPPS)
-all-install: $(ALLINSTALL_MODULES) allinstall-Kernel $(ALLINSTALL_USRLIBS) $(ALLINSTALL_USRAPPS)
-clean: $(CLEAN_MODULES) clean-Kernel $(CLEAN_USRLIBS) $(CLEAN_USRAPPS)
-install: $(INSTALL_MODULES) install-Kernel $(INSTALL_USRLIBS) $(INSTALL_USRAPPS)
+all: $(ALL_DYNMODS) $(ALL_MODULES) all-Kernel $(ALL_USRLIBS) $(ALL_USRAPPS)
+all-install: $(AI_DYNMODS) $(AI_MODULES) allinstall-Kernel $(AI_USRLIBS) $(AI_USRAPPS)
+clean: $(CLEAN_DYNMODS) $(CLEAN_MODULES) clean-Kernel $(CLEAN_USRLIBS) $(CLEAN_USRAPPS)
+install: $(INSTALL_DYNMODS) $(INSTALL_MODULES) install-Kernel $(INSTALL_USRLIBS) $(INSTALL_USRAPPS)
# Compile Only
$(ALL_MODULES): all-%:
@echo === User Application: $* && $(SUBMAKE) all -C Usermode/Applications/$*_src
# Compile & Install
-$(ALLINSTALL_MODULES): allinstall-%:
+#$(AI_DYNMODS): allinstall-%:
+# @echo === Dynamic Module: $* && STATIC_MODULE=yes $(SUBMAKE) all install -C Modules/$*
+$(AI_MODULES): allinstall-%:
@echo === Module: $* && $(SUBMAKE) all install -C Modules/$*
allinstall-Kernel:
@echo === Kernel && $(SUBMAKE) all install -C Kernel
-$(ALLINSTALL_USRLIBS): allinstall-%:
+$(AI_USRLIBS): allinstall-%:
@echo === User Library: $* && $(SUBMAKE) all install -C Usermode/Libraries/$*_src
-$(ALLINSTALL_USRAPPS): allinstall-%:
+$(AI_USRAPPS): allinstall-%:
@echo === User Application: $* && $(SUBMAKE) all install -C Usermode/Applications/$*_src
# Clean up compilation
ARCHDIR = x86
endif
-FILESYSTEMS = fat
+FILESYSTEMS =
DRIVERS =
MODULES = Storage/ATA Storage/FDD
MODULES += Network/NE2000
-MODULES += Display/BochsGA
-MODULES += Filesystems/FS_Ext2
+MODULES += Display/VESA
+#MODULES += Display/BochsGA
+MODULES += Filesystems/Ext2
+MODULES += Filesystems/FAT
MODULES += IPStack
-DYNMODS = USB Interfaces/UDI
+DYNMODS = USB/Core Interfaces/UDI
#DISTROOT = /mnt/AcessHDD/Acess2
#DISTROOT = ~/Projects/Acess2/Filesystem
/**\r
* \file drv_bochsvbe.c\r
- * \brief BGA (Bochs Graphic Adapter) Driver\r
- * \note for Acess2\r
+ * \brief BGA (Bochs Graphic Adapter) Driver for Acess2\r
* \warning This driver does NOT support the Bochs PCI VGA driver\r
*/\r
#define DEBUG 0\r
\r
#define INT\r
\r
-// === TYPEDEFS ===\r
-typedef struct {\r
+// === TYPES ===\r
+typedef struct sBGA_Mode {\r
Uint16 width;\r
Uint16 height;\r
Uint16 bpp;\r
- Uint16 flags;\r
Uint32 fbSize;\r
-} t_bga_mode;\r
+} tBGA_Mode;\r
\r
// === CONSTANTS ===\r
-enum eMode_Flags {\r
- MODEFLAG_TEXT = 1\r
-};\r
#define BGA_LFB_MAXSIZE (1024*768*4)\r
#define VBE_DISPI_BANK_ADDRESS 0xA0000\r
#define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000\r
int BGA_Ioctl(tVFS_Node *node, int id, void *data);\r
\r
// === GLOBALS ===\r
-MODULE_DEFINE(0, 0x0032, BochsGA, BGA_Install, NULL, NULL);\r
+MODULE_DEFINE(0, 0x0032, BochsGA, BGA_Install, NULL, "PCI", NULL);\r
tDevFS_Driver gBGA_DriverStruct = {\r
NULL, "BochsGA",\r
{\r
}\r
};\r
int giBGA_CurrentMode = -1;\r
+ int giBGA_BufferFormat = 0;\r
tVideo_IOCtl_Pos gBGA_CursorPos = {-1,-1};\r
- int giBGA_DriverId = -1;\r
Uint *gBGA_Framebuffer;\r
-t_bga_mode gBGA_Modes[] = {\r
+tBGA_Mode gpBGA_CurrentMode;\r
+const tBGA_Mode gBGA_Modes[] = {\r
{},\r
- { 80,25, 12, MODEFLAG_TEXT, 80*25*8}, // 640 x 480\r
- {100,37, 12, MODEFLAG_TEXT, 100*37*8}, // 800 x 600\r
- {640,480,8, 0, 640*480},\r
{640,480,32, 0, 640*480*4},\r
- {800,600,8, 0, 800*600},\r
{800,600,32, 0, 800*600*4},\r
+ {1024,768,32, 0, 1024*768*4}\r
};\r
#define BGA_MODE_COUNT (sizeof(gBGA_Modes)/sizeof(gBGA_Modes[0]))\r
\r
*/\r
int BGA_Install(char **Arguments)\r
{\r
- int bga_version = 0;\r
+ int version = 0;\r
\r
// Check BGA Version\r
- bga_version = BGA_int_ReadRegister(VBE_DISPI_INDEX_ID);\r
+ version = BGA_int_ReadRegister(VBE_DISPI_INDEX_ID);\r
+ \r
// NOTE: This driver was written for 0xB0C4, but they seem to be backwards compatable\r
- if(bga_version < 0xB0C4 || bga_version > 0xB0C5) {\r
- Warning("[BGA ] Bochs Adapter Version is not 0xB0C4 or 0xB0C5, instead 0x%x", bga_version);\r
- return 0;\r
+ if(version < 0xB0C4 || version > 0xB0C5) {\r
+ Log_Warning("BGA", "Bochs Adapter Version is not 0xB0C4 or 0xB0C5, instead 0x%x", version);\r
+ return MODULE_ERR_NOTNEEDED;\r
}\r
\r
// Install Device\r
- giBGA_DriverId = DevFS_AddDevice( &gBGA_DriverStruct );\r
- if(giBGA_DriverId == -1) {\r
- Warning("[BGA ] Unable to register with DevFS, maybe already loaded?");\r
- return 0;\r
+ if(DevFS_AddDevice( &gBGA_DriverStruct ) == -1) {\r
+ Log_Warning("BGA", "Unable to register with DevFS, maybe already loaded?");\r
+ return MODULE_ERR_MISC;\r
}\r
\r
// Map Framebuffer to hardware address\r
gBGA_Framebuffer = (void *) MM_MapHWPage(VBE_DISPI_LFB_PHYSICAL_ADDRESS, 768); // 768 pages (3Mb)\r
\r
- return 1;\r
+ return MODULE_ERR_OK;\r
}\r
\r
/**\r
*/\r
void BGA_Uninstall()\r
{\r
- //DevFS_DelDevice( giBGA_DriverId );\r
+ DevFS_DelDevice( &gBGA_DriverStruct );\r
MM_UnmapHWPage( VBE_DISPI_LFB_PHYSICAL_ADDRESS, 768 );\r
}\r
\r
if(giBGA_CurrentMode == -1) return -1;\r
\r
// Check Offset and Length against Framebuffer Size\r
- if(off+len > gBGA_Modes[giBGA_CurrentMode].fbSize)\r
+ if(off+len > gpBGA_CurrentMode->fbSize)\r
return -1;\r
\r
// Copy from Framebuffer\r
return -1;\r
}\r
\r
- // Check Input against Frambuffer Size\r
- if(off + len > gBGA_Modes[giBGA_CurrentMode].fbSize) {\r
- LEAVE('i', -1);\r
- return -1;\r
- }\r
- \r
// Text Mode\r
- if( gBGA_Modes[giBGA_CurrentMode].flags & MODEFLAG_TEXT )\r
+ switch( giBGA_BufferFormat )\r
{\r
+ case VIDEO_BUFFMT_TEXT:\r
+ {\r
tVT_Char *chars = Buffer;\r
- int pitch = gBGA_Modes[giBGA_CurrentMode].width * giVT_CharWidth;\r
+ int pitch = gpBGA_CurrentMode->width * giVT_CharWidth;\r
int x, y;\r
Uint32 *dest;\r
\r
off /= sizeof(tVT_Char);\r
dest = (void*)gBGA_Framebuffer;\r
- x = (off % gBGA_Modes[giBGA_CurrentMode].width) * giVT_CharWidth;\r
- y = (off / gBGA_Modes[giBGA_CurrentMode].width) * giVT_CharHeight;\r
+ x = (off % gpBGA_CurrentMode->width) * giVT_CharWidth;\r
+ y = (off / gpBGA_CurrentMode->width) * giVT_CharHeight;\r
+ \r
+ // Sanity Check\r
+ if(y > gpBGA_CurrentMode->height) {\r
+ LEAVE('i', 0);\r
+ return 0;\r
+ }\r
+ \r
dest += y * pitch;\r
dest += x * giVT_CharWidth;\r
len /= sizeof(tVT_Char);\r
dest += pitch*(giVT_CharHeight-1);\r
}\r
}\r
- }\r
- else\r
- {\r
+ }\r
+ break;\r
+ \r
+ case VIDEO_BUFFMT_FRAMEBUFFER:\r
+ {\r
Uint8 *destBuf = (Uint8*) ((Uint)gBGA_Framebuffer + (Uint)off);\r
\r
- Log("buffer = %p", Buffer);\r
- Log("Updating Framebuffer (%p to %p)",\r
- destBuf, destBuf + (Uint)len);\r
+ if( off + len > gpBGA_CurrentMode->fbSize ) {\r
+ LEAVE('i', 0);\r
+ return 0;\r
+ }\r
+ \r
+ LOG("buffer = %p", Buffer);\r
+ LOG("Updating Framebuffer (%p to %p)", destBuf, destBuf + (Uint)len);\r
\r
\r
// Copy to Frambuffer\r
memcpy(destBuf, Buffer, len);\r
\r
- Log("BGA Framebuffer updated");\r
+ LOG("BGA Framebuffer updated");\r
+ }\r
+ break;\r
+ default:\r
+ LEAVE('i', -1);\r
+ return -1;\r
}\r
\r
LEAVE('i', len);\r
}\r
\r
/**\r
- * \fn INT int BGA_Ioctl(tVFS_Node *node, int ID, void *Data)\r
+ * \fn int BGA_Ioctl(tVFS_Node *Node, int ID, void *Data)\r
* \brief Handle messages to the device\r
*/\r
-INT int BGA_Ioctl(tVFS_Node *node, int ID, void *Data)\r
+int BGA_Ioctl(tVFS_Node *Node, int ID, void *Data)\r
{\r
int ret = -2;\r
- ENTER("pNode iId pData", node, ID, Data);\r
+ ENTER("pNode iId pData", Node, ID, Data);\r
\r
switch(ID)\r
{\r
ret = BGA_int_ModeInfo((tVideo_IOCtl_Mode*)Data);\r
break;\r
\r
- // Request Access to LFB\r
- case VIDEO_IOCTL_REQLFB:\r
- ret = BGA_int_MapFB( *(void**)Data );\r
+ case VIDEO_IOCTL_SETBUFFORMAT:\r
+ ret = giBGA_BufferFormat;\r
+ if(Data)\r
+ giBGA_BufferFormat = *(int*)Data;\r
break;\r
\r
case VIDEO_IOCTL_SETCURSOR:\r
gBGA_CursorPos.y = ((tVideo_IOCtl_Pos*)Data)->y;\r
break;\r
\r
+ // Request Access to LFB\r
+ case VIDEO_IOCTL_REQLFB:\r
+ ret = BGA_int_MapFB( *(void**)Data );\r
+ break;\r
+ \r
default:\r
LEAVE('i', -2);\r
return -2;\r
outw(VBE_DISPI_IOPORT_DATA, value);\r
}\r
\r
-INT Uint16 BGA_int_ReadRegister(Uint16 reg)\r
+Uint16 BGA_int_ReadRegister(Uint16 reg)\r
{\r
outw(VBE_DISPI_IOPORT_INDEX, reg);\r
return inw(VBE_DISPI_IOPORT_DATA);\r
}\r
\r
#if 0\r
-INT void BGA_int_SetBank(Uint16 bank)\r
+void BGA_int_SetBank(Uint16 bank)\r
{\r
BGA_int_WriteRegister(VBE_DISPI_INDEX_BANK, bank);\r
}\r
* \fn void BGA_int_SetMode(Uint16 width, Uint16 height, Uint16 bpp)\r
* \brief Sets the video mode from the dimensions and bpp given\r
*/\r
-void BGA_int_SetMode(Uint16 width, Uint16 height)\r
+void BGA_int_SetMode(Uint16 Width, Uint16 Height)\r
{\r
- ENTER("iwidth iheight ibpp", width, height, bpp);\r
+ ENTER("iWidth iheight ibpp", Width, Height, bpp);\r
BGA_int_WriteRegister(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED);\r
- BGA_int_WriteRegister(VBE_DISPI_INDEX_XRES, width);\r
- BGA_int_WriteRegister(VBE_DISPI_INDEX_YRES, height);\r
+ BGA_int_WriteRegister(VBE_DISPI_INDEX_XRES, Width);\r
+ BGA_int_WriteRegister(VBE_DISPI_INDEX_YRES, Height);\r
BGA_int_WriteRegister(VBE_DISPI_INDEX_BPP, 32);\r
BGA_int_WriteRegister(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED | VBE_DISPI_NOCLEARMEM | VBE_DISPI_LFB_ENABLED);\r
- //BGA_int_WriteRegister(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED | VBE_DISPI_NOCLEARMEM);\r
LEAVE('-');\r
}\r
\r
gBGA_Modes[id].height);\r
\r
giBGA_CurrentMode = id;\r
+ gpBGA_CurrentMode = &gBGA_Modes[id];\r
return id;\r
}\r
\r
\r
// Sanity Check\r
if((Uint)Dest > 0xC0000000) return 0;\r
- if(gBGA_Modes[giBGA_CurrentMode].bpp < 15) return 0; // Only non-pallete modes are supported\r
+ if(gpBGA_CurrentMode->bpp < 15) return 0; // Only non-pallete modes are supported\r
\r
// Count required pages\r
- pages = (gBGA_Modes[giBGA_CurrentMode].fbSize + 0xFFF) >> 12;\r
+ pages = (gpBGA_CurrentMode->fbSize + 0xFFF) >> 12;\r
\r
// Check if there is space\r
for( i = 0; i < pages; i++ )\r
+CATEGORY = Video
+
-include ../../Makefile.tpl
--- /dev/null
+#
+#
+
+OBJ = main.o
+NAME = VESA
+
+-include ../Makefile.tpl
--- /dev/null
+/**
+ */
+#ifndef _COMMON_H_
+#define _COMMON_H_
+
+// === TYPES ===
+typedef struct sFarPtr
+{
+ Uint16 ofs;
+ Uint16 seg;
+} tFarPtr;
+
+typedef struct sVesa_Mode
+{
+ Uint16 code;
+ Uint16 width, height;
+ Uint16 pitch, bpp;
+ Uint16 flags;
+ Uint32 fbSize;
+ Uint32 framebuffer;
+} tVesa_Mode;
+
+typedef struct sVesa_CallModeInfo
+{
+ Uint16 attributes;
+ Uint8 winA,winB;
+ Uint16 granularity;
+ Uint16 winsize;
+ Uint16 segmentA, segmentB;
+ tFarPtr realFctPtr;
+ Uint16 pitch; // Bytes per scanline
+
+ Uint16 Xres, Yres;
+ Uint8 Wchar, Ychar, planes, bpp, banks;
+ Uint8 memory_model, bank_size, image_pages;
+ Uint8 reserved0;
+
+ Uint8 red_mask, red_position;
+ Uint8 green_mask, green_position;
+ Uint8 blue_mask, blue_position;
+ Uint8 rsv_mask, rsv_position;
+ Uint8 directcolor_attributes;
+
+ Uint32 physbase; // Your LFB address ;)
+ Uint32 reserved1;
+ Sint16 reserved2;
+} tVesa_CallModeInfo;
+
+typedef struct sVesa_CallInfo
+{
+ char signature[4]; // == "VESA"
+ Uint16 Version; // == 0x0300 for Vesa 3.0
+ tFarPtr OEMString; // isa vbeFarPtr
+ Uint8 Capabilities[4];
+ tFarPtr VideoModes; // isa vbeParPtr
+ Uint16 TotalMemory; // as # of 64KB blocks
+} tVesa_CallInfo;
+
+#endif
--- /dev/null
+/*\r
+ * AcessOS 1\r
+ * Video BIOS Extensions (Vesa) Driver\r
+ */\r
+#define DEBUG 1\r
+#define VERSION 0x100\r
+\r
+#include <acess.h>\r
+#include <vfs.h>\r
+#include <tpl_drv_video.h>\r
+#include <fs_devfs.h>\r
+#include <modules.h>\r
+#include <vm8086.h>\r
+#include "common.h"\r
+\r
+// === CONSTANTS ===\r
+#define FLAG_LFB 0x1\r
+\r
+// === PROTOTYPES ===\r
+ int Vesa_Install(char **Arguments);\r
+Uint64 Vesa_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);\r
+Uint64 Vesa_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);\r
+ int Vesa_Ioctl(tVFS_Node *Node, int ID, void *Data);\r
+ int Vesa_Int_SetMode(int Mode);\r
+ int Vesa_Int_FindMode(tVideo_IOCtl_Mode *data);\r
+ int Vesa_Int_ModeInfo(tVideo_IOCtl_Mode *data);\r
+\r
+// === GLOBALS ===\r
+MODULE_DEFINE(0, VERSION, Vesa, Vesa_Install, NULL, "PCI", "VM8086", NULL);\r
+tDevFS_Driver gVesa_DriverStruct = {\r
+ NULL, "Vesa",\r
+ {\r
+ .Read = Vesa_Read,\r
+ .Write = Vesa_Write,\r
+ .IOCtl = Vesa_Ioctl\r
+ }\r
+};\r
+tSpinlock glVesa_Lock;\r
+tVM8086 *gpVesa_BiosState;\r
+ int giVesaCurrentMode = -1;\r
+ int giVesaCurrentFormat = VIDEO_BUFFMT_TEXT;\r
+ int giVesaDriverId = -1;\r
+char *gVesaFramebuffer = (void*)0xC00A0000;\r
+tVesa_Mode *gVesa_Modes;\r
+ int giVesaModeCount = 0;\r
+ int giVesaPageCount = 0;\r
+\r
+//CODE\r
+int Vesa_Install(char **Arguments)\r
+{\r
+ tVesa_CallInfo *info;\r
+ tFarPtr infoPtr;\r
+ tVesa_CallModeInfo *modeinfo;\r
+ tFarPtr modeinfoPtr;\r
+ Uint16 *modes;\r
+ int i;\r
+ \r
+ // Allocate Info Block\r
+ gpVesa_BiosState = VM8086_Init();\r
+ info = VM8086_Allocate(gpVesa_BiosState, 512, &infoPtr.seg, &infoPtr.ofs);\r
+ modeinfo = VM8086_Allocate(gpVesa_BiosState, 512, &modeinfoPtr.seg, &modeinfoPtr.ofs);\r
+ // Set Requested Version\r
+ memcpy(info->signature, "VBE2", 4);\r
+ // Set Registers\r
+ gpVesa_BiosState->AX = 0x4F00;\r
+ gpVesa_BiosState->ES = infoPtr.seg; gpVesa_BiosState->DI = infoPtr.ofs;\r
+ // Call Interrupt\r
+ VM8086_Int(gpVesa_BiosState, 0x10);\r
+ if(gpVesa_BiosState->AX != 0x004F) {\r
+ Log_Warning("Vesa", "Vesa_Install - VESA/VBE Unsupported (AX = 0x%x)\n", gpVesa_BiosState->AX);\r
+ return MODULE_ERR_NOTNEEDED;\r
+ }\r
+ \r
+ Log_Debug("Vesa", "info->VideoModes = %04x:%04x", info->VideoModes.seg, info->VideoModes.ofs);\r
+ modes = (Uint16 *) VM8086_GetPointer(gpVesa_BiosState, info->VideoModes.seg, info->VideoModes.ofs);\r
+ \r
+ // Read Modes\r
+ for( giVesaModeCount = 0; modes[giVesaModeCount] != 0xFFFF; giVesaModeCount++ );\r
+ gVesa_Modes = (tVesa_Mode *)malloc( giVesaModeCount * sizeof(tVesa_Mode) );\r
+ \r
+ // Insert Text Mode\r
+ gVesa_Modes[0].width = 80;\r
+ gVesa_Modes[0].height = 25;\r
+ gVesa_Modes[0].bpp = 12;\r
+ gVesa_Modes[0].code = 0x3;\r
+ gVesa_Modes[0].flags = 1;\r
+ gVesa_Modes[0].fbSize = 80*25*2;\r
+ gVesa_Modes[0].framebuffer = 0xB8000;\r
+ \r
+ for( i = 1; i < giVesaModeCount; i++ )\r
+ {\r
+ gVesa_Modes[i].code = modes[i];\r
+ // Get Mode info\r
+ gpVesa_BiosState->AX = 0x4F01;\r
+ gpVesa_BiosState->CX = gVesa_Modes[i].code;\r
+ gpVesa_BiosState->ES = modeinfoPtr.seg;\r
+ gpVesa_BiosState->DI = modeinfoPtr.ofs;\r
+ VM8086_Int(gpVesa_BiosState, 0x10);\r
+ \r
+ // Parse Info\r
+ gVesa_Modes[i].flags = 0;\r
+ if ( (modeinfo->attributes & 0x90) == 0x90 )\r
+ {\r
+ gVesa_Modes[i].flags |= FLAG_LFB;\r
+ gVesa_Modes[i].framebuffer = modeinfo->physbase;\r
+ gVesa_Modes[i].fbSize = modeinfo->Xres*modeinfo->Yres*modeinfo->bpp/8;\r
+ } else {\r
+ gVesa_Modes[i].framebuffer = 0;\r
+ gVesa_Modes[i].fbSize = 0;\r
+ }\r
+ \r
+ gVesa_Modes[i].width = modeinfo->Xres;\r
+ gVesa_Modes[i].height = modeinfo->Yres;\r
+ gVesa_Modes[i].bpp = modeinfo->bpp;\r
+ \r
+ #if DEBUG\r
+ Log_Log("Vesa", "0x%x - %ix%ix%i",\r
+ gVesa_Modes[i].code, gVesa_Modes[i].width, gVesa_Modes[i].height, gVesa_Modes[i].bpp);\r
+ #endif\r
+ }\r
+ \r
+ \r
+ // Install Device\r
+ giVesaDriverId = DevFS_AddDevice( &gVesa_DriverStruct );\r
+ if(giVesaDriverId == -1) return MODULE_ERR_MISC;\r
+ \r
+ return MODULE_ERR_OK;\r
+}\r
+\r
+/* Read from the framebuffer\r
+ */\r
+Uint64 Vesa_Read(tVFS_Node *Node, Uint64 off, Uint64 len, void *buffer)\r
+{\r
+ #if DEBUG >= 2\r
+ LogF("Vesa_Read: () - NULL\n");\r
+ #endif\r
+ return 0;\r
+}\r
+\r
+/**\r
+ * \brief Write to the framebuffer\r
+ */\r
+Uint64 Vesa_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
+{\r
+ ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);\r
+\r
+ if(Buffer == NULL) {\r
+ LEAVE('i', 0);\r
+ return 0;\r
+ }\r
+\r
+ // Default Text mode\r
+ if( giVesaCurrentMode == 0 )\r
+ {\r
+ Uint8 *fb = (Uint8 *)(KERNEL_BASE|0xB8000);\r
+ Uint32 *buf = Buffer;\r
+ int rem;\r
+ \r
+ if( giVesaCurrentFormat != VIDEO_BUFFMT_TEXT ) {\r
+ Log_Warning("VESA", "Vesa_Write - Mode 0 is not framebuffer");\r
+ LEAVE('i', -1);\r
+ return -1;\r
+ }\r
+ \r
+ if( Offset + Length > 25*80*8 ) {\r
+ Log_Warning("VESA", "Vesa_Write - Framebuffer Overflow");\r
+ LEAVE('i', 0);\r
+ return 0;\r
+ }\r
+ \r
+ fb += 2*Offset;\r
+ for(rem = Length / sizeof(tVT_Char); rem --; fb += 2)\r
+ {\r
+ if( *buf < 0x80 )\r
+ *fb = *buf & 0x7F;\r
+ else\r
+ *fb = 0x00;\r
+ buf ++;\r
+ \r
+ fb[1] = 0;\r
+ fb[1] |= (*buf & 0x888) == 0x888 ? 0x8 : 0;\r
+ fb[1] |= (*buf & 0x700) > 0x300 ? 0x4 : 0;\r
+ fb[1] |= (*buf & 0x070) > 0x030 ? 0x2 : 0;\r
+ fb[1] |= (*buf & 0x007) > 0x003 ? 0x1 : 0;\r
+ fb[1] |= (*buf & 0x888000) == 0x888000 ? 0x80 : 0;\r
+ fb[1] |= (*buf & 0x700000) > 0x300000 ? 0x40 : 0;\r
+ fb[1] |= (*buf & 0x070000) > 0x030000 ? 0x20 : 0;\r
+ fb[1] |= (*buf & 0x007000) > 0x003000 ? 0x10 : 0;\r
+ buf ++;\r
+ }\r
+ Length /= sizeof(tVT_Char);\r
+ Length *= sizeof(tVT_Char);\r
+ LEAVE('X', Length);\r
+ return Length;\r
+ }\r
+\r
+ if( gVesa_Modes[giVesaCurrentMode].framebuffer == 0 ) {\r
+ Log_Warning("VESA", "Vesa_Write - Non-LFB Modes not yet supported.");\r
+ LEAVE('i', 0);\r
+ return 0;\r
+ }\r
+ \r
+ // Text Mode\r
+ switch( giVesaCurrentFormat )\r
+ {\r
+ case VIDEO_BUFFMT_TEXT:\r
+ {\r
+ tVT_Char *chars = Buffer;\r
+ int pitch = gVesa_Modes[giVesaCurrentMode].width * giVT_CharWidth;\r
+ int x, y;\r
+ Uint32 *dest;\r
+ int rem;\r
+ \r
+ Offset /= sizeof(tVT_Char);\r
+ dest = (void*)gVesaFramebuffer;\r
+ x = (Offset % gVesa_Modes[giVesaCurrentMode].width) * giVT_CharWidth;\r
+ y = (Offset / gVesa_Modes[giVesaCurrentMode].width) * giVT_CharHeight;\r
+ \r
+ // Sanity Check\r
+ if(y > gVesa_Modes[giVesaCurrentMode].height) {\r
+ LEAVE('i', 0);\r
+ return 0;\r
+ }\r
+ \r
+ dest += y * pitch;\r
+ dest += x * giVT_CharWidth;\r
+ for( rem = Length / sizeof(tVT_Char); rem--; )\r
+ {\r
+ VT_Font_Render(\r
+ chars->Ch,\r
+ dest, pitch,\r
+ VT_Colour12to24(chars->BGCol),\r
+ VT_Colour12to24(chars->FGCol)\r
+ );\r
+ \r
+ dest += giVT_CharWidth;\r
+ \r
+ chars ++;\r
+ x += giVT_CharWidth;\r
+ if( x >= pitch ) {\r
+ x = 0;\r
+ y += giVT_CharHeight;\r
+ dest += pitch*(giVT_CharHeight-1);\r
+ }\r
+ }\r
+ Length /= sizeof(tVT_Char);\r
+ Length *= sizeof(tVT_Char);\r
+ }\r
+ break;\r
+ \r
+ case VIDEO_BUFFMT_FRAMEBUFFER:\r
+ {\r
+ Uint8 *destBuf = (Uint8*) ((Uint)gVesaFramebuffer + (Uint)Offset);\r
+ \r
+ if(gVesa_Modes[giVesaCurrentMode].fbSize < Offset+Length)\r
+ {\r
+ Log_Warning("VESA", "Vesa_Write - Framebuffer Overflow");\r
+ LEAVE('i', 0);\r
+ return 0;\r
+ }\r
+ \r
+ LOG("buffer = %p", Buffer);\r
+ LOG("Updating Framebuffer (%p to %p)", destBuf, destBuf + (Uint)Length);\r
+ \r
+ \r
+ // Copy to Frambuffer\r
+ memcpy(destBuf, Buffer, Length);\r
+ \r
+ LOG("BGA Framebuffer updated");\r
+ }\r
+ break;\r
+ default:\r
+ LEAVE('i', -1);\r
+ return -1;\r
+ }\r
+ \r
+ LEAVE('X', Length);\r
+ return Length;\r
+}\r
+\r
+/**\r
+ * \fn int Vesa_Ioctl(vfs_node *node, int id, void *data)\r
+ * \brief Handle messages to the device\r
+ */\r
+int Vesa_Ioctl(tVFS_Node *Node, int ID, void *Data)\r
+{\r
+ int ret;\r
+ switch(ID)\r
+ {\r
+ case DRV_IOCTL_TYPE: return DRV_TYPE_VIDEO;\r
+ case DRV_IOCTL_IDENT: memcpy("VESA", Data, 4); return 1;\r
+ case DRV_IOCTL_VERSION: return VERSION;\r
+ \r
+ case VIDEO_IOCTL_GETSETMODE:\r
+ if( !Data ) return giVesaCurrentMode;\r
+ return Vesa_Int_SetMode( *(int*)Data );\r
+ \r
+ case VIDEO_IOCTL_FINDMODE:\r
+ return Vesa_Int_FindMode((tVideo_IOCtl_Mode*)Data);\r
+ case VIDEO_IOCTL_MODEINFO:\r
+ return Vesa_Int_ModeInfo((tVideo_IOCtl_Mode*)Data);\r
+ \r
+ case VIDEO_IOCTL_SETBUFFORMAT:\r
+ ret = giVesaCurrentFormat;\r
+ if(Data) giVesaCurrentFormat = *(int*)Data;\r
+ return ret;\r
+ \r
+ case VIDEO_IOCTL_REQLFB: // Request Linear Framebuffer\r
+ return 0;\r
+ }\r
+ return 0;\r
+}\r
+\r
+int Vesa_Int_SetMode(int mode)\r
+{ \r
+ #if DEBUG\r
+ LogF("Vesa_Int_SetMode: (mode=%i)\n", mode);\r
+ #endif\r
+ \r
+ // Sanity Check values\r
+ if(mode < 0 || mode > giVesaModeCount) return -1;\r
+ \r
+ // Check for fast return\r
+ if(mode == giVesaCurrentMode) return 1;\r
+ \r
+ LOCK( &glVesa_Lock );\r
+ \r
+ gpVesa_BiosState->AX = 0x4F02;\r
+ gpVesa_BiosState->BX = gVesa_Modes[mode].code;\r
+ if(gVesa_Modes[mode].flags & FLAG_LFB) {\r
+ Log_Log("VESA", "Using LFB");\r
+ gpVesa_BiosState->BX |= 0x4000; // Bit 14 - Use LFB\r
+ }\r
+ \r
+ // Set Mode\r
+ VM8086_Int(gpVesa_BiosState, 0x10);\r
+ \r
+ // Map Framebuffer\r
+ MM_UnmapHWPages((tVAddr)gVesaFramebuffer, giVesaPageCount);\r
+ giVesaPageCount = (gVesa_Modes[mode].fbSize + 0xFFF) >> 12;\r
+ gVesaFramebuffer = (void*)MM_MapHWPages(gVesa_Modes[mode].framebuffer, giVesaPageCount);\r
+ \r
+ LogF("Vesa", "Framebuffer (Phys) = 0x%x", gVesa_Modes[mode].framebuffer);\r
+ LogF("Vesa", "Framebuffer (Virt) = 0x%x", gVesaFramebuffer);\r
+ \r
+ // Record Mode Set\r
+ giVesaCurrentMode = mode;\r
+ \r
+ RELEASE( &glVesa_Lock );\r
+ \r
+ return 1;\r
+}\r
+\r
+int Vesa_Int_FindMode(tVideo_IOCtl_Mode *data)\r
+{\r
+ int i;\r
+ int best = -1, bestFactor = 1000;\r
+ int factor, tmp;\r
+ \r
+ ENTER("idata->width idata->height idata->bpp", data->width, data->height, data->bpp);\r
+ \r
+ for(i=0;i<giVesaModeCount;i++)\r
+ {\r
+ LOG("Mode %i (%ix%ix%i)", i, gVesa_Modes[i].width, gVesa_Modes[i].height, gVesa_Modes[i].bpp);\r
+ \r
+ if(gVesa_Modes[i].width == data->width\r
+ && gVesa_Modes[i].height == data->height\r
+ && gVesa_Modes[i].bpp == data->bpp)\r
+ {\r
+ LOG("Perfect!");\r
+ best = i;\r
+ break;\r
+ }\r
+ \r
+ tmp = gVesa_Modes[i].width * gVesa_Modes[i].height * gVesa_Modes[i].bpp;\r
+ tmp -= data->width * data->height * data->bpp;\r
+ tmp = tmp < 0 ? -tmp : tmp;\r
+ factor = tmp * 100 / (data->width * data->height * data->bpp);\r
+ \r
+ LOG("factor = %i", factor);\r
+ \r
+ if(factor < bestFactor)\r
+ {\r
+ bestFactor = factor;\r
+ best = i;\r
+ }\r
+ }\r
+ data->id = best;\r
+ data->width = gVesa_Modes[best].width;\r
+ data->height = gVesa_Modes[best].height;\r
+ data->bpp = gVesa_Modes[best].bpp;\r
+ LEAVE('i', best);\r
+ return best;\r
+}\r
+\r
+int Vesa_Int_ModeInfo(tVideo_IOCtl_Mode *data)\r
+{\r
+ if(data->id < 0 || data->id > giVesaModeCount) return -1;\r
+ data->width = gVesa_Modes[data->id].width;\r
+ data->height = gVesa_Modes[data->id].height;\r
+ data->bpp = gVesa_Modes[data->id].bpp;\r
+ return 1;\r
+}\r
--- /dev/null
+#
+#
+
+OBJ = ext2.o read.o dir.o write.o
+NAME = Ext2
+
+-include ../Makefile.tpl
--- /dev/null
+/*
+ * Acess OS
+ * Ext2 Driver Version 1
+ */
+/**
+ * \file dir.c
+ * \brief Second Extended Filesystem Driver
+ * \todo Implement file full write support
+ */
+#define DEBUG 1
+#define VERBOSE 0
+#include "ext2_common.h"
+
+
+// === PROTOTYPES ===
+char *Ext2_ReadDir(tVFS_Node *Node, int Pos);
+tVFS_Node *Ext2_FindDir(tVFS_Node *Node, char *FileName);
+ int Ext2_MkNod(tVFS_Node *Node, char *Name, Uint Flags);
+tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeId, char *Name);
+
+// === CODE ===
+/**
+ \fn char *Ext2_ReadDir(tVFS_Node *Node, int Pos)
+ \brief Reads a directory entry
+*/
+char *Ext2_ReadDir(tVFS_Node *Node, int Pos)
+{
+ tExt2_Inode inode;
+ char namebuf[EXT2_NAME_LEN+1];
+ tExt2_DirEnt dirent;
+ Uint64 Base; // Block's Base Address
+ int block = 0, ofs = 0;
+ int entNum = 0;
+ tExt2_Disk *disk = Node->ImplPtr;
+ Uint size;
+
+ ENTER("pNode iPos", Node, Pos);
+
+ // Read directory's inode
+ //Ext2_int_GetInode(Node, &inode);
+ Ext2_int_ReadInode(disk, Node->Inode, &inode);
+ size = inode.i_size;
+
+ LOG("inode.i_block[0] = 0x%x", inode.i_block[0]);
+
+ // Find Entry
+ // Get First Block
+ // - Do this ourselves as it is a simple operation
+ Base = inode.i_block[0] * disk->BlockSize;
+ while(Pos -- && size > 0)
+ {
+ VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent);
+ ofs += dirent.rec_len;
+ size -= dirent.rec_len;
+ entNum ++;
+
+ if(ofs >= disk->BlockSize) {
+ block ++;
+ if( ofs > disk->BlockSize ) {
+ Log_Warning("EXT2", "Directory Entry %i of inode %i extends over a block boundary, ignoring",
+ entNum-1, Node->Inode);
+ }
+ ofs = 0;
+ Base = Ext2_int_GetBlockAddr( disk, inode.i_block, block );
+ }
+ }
+
+ // Check for the end of the list
+ if(size <= 0) {
+ LEAVE('n');
+ return NULL;
+ }
+
+ // Read Entry
+ VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent );
+ //LOG("dirent.inode = %i", dirent.inode);
+ //LOG("dirent.rec_len = %i", dirent.rec_len);
+ //LOG("dirent.name_len = %i", dirent.name_len);
+ VFS_ReadAt( disk->FD, Base+ofs+sizeof(tExt2_DirEnt), dirent.name_len, namebuf );
+ namebuf[ dirent.name_len ] = '\0'; // Cap off string
+
+
+ // Ignore . and .. (these are done in the VFS)
+ if( (namebuf[0] == '.' && namebuf[1] == '\0')
+ || (namebuf[0] == '.' && namebuf[1] == '.' && namebuf[2]=='\0')) {
+ LEAVE('p', VFS_SKIP);
+ return VFS_SKIP; // Skip
+ }
+
+ LEAVE('s', namebuf);
+ // Create new node
+ return strdup(namebuf);
+}
+
+/**
+ \fn tVFS_Node *Ext2_FindDir(tVFS_Node *node, char *filename)
+ \brief Gets information about a file
+ \param node vfs node - Parent Node
+ \param filename String - Name of file
+ \return VFS Node of file
+*/
+tVFS_Node *Ext2_FindDir(tVFS_Node *Node, char *Filename)
+{
+ tExt2_Disk *disk = Node->ImplPtr;
+ tExt2_Inode inode;
+ char namebuf[EXT2_NAME_LEN+1];
+ tExt2_DirEnt dirent;
+ Uint64 Base; // Block's Base Address
+ int block = 0, ofs = 0;
+ int entNum = 0;
+ Uint size;
+
+ // Read directory's inode
+ Ext2_int_ReadInode(disk, Node->Inode, &inode);
+ size = inode.i_size;
+
+ // Get First Block
+ // - Do this ourselves as it is a simple operation
+ Base = inode.i_block[0] * disk->BlockSize;
+ // Find File
+ while(size > 0)
+ {
+ VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent);
+ VFS_ReadAt( disk->FD, Base+ofs+sizeof(tExt2_DirEnt), dirent.name_len, namebuf );
+ namebuf[ dirent.name_len ] = '\0'; // Cap off string
+ // If it matches, create a node and return it
+ if(strcmp(namebuf, Filename) == 0)
+ return Ext2_int_CreateNode( disk, dirent.inode, namebuf );
+ // Increment pointers
+ ofs += dirent.rec_len;
+ size -= dirent.rec_len;
+ entNum ++;
+
+ // Check for end of block
+ if(ofs >= disk->BlockSize) {
+ block ++;
+ if( ofs > disk->BlockSize ) {
+ Log_Warning("EXT2", "Directory Entry %i of inode %i extends over a block boundary, ignoring",
+ entNum-1, Node->Inode);
+ }
+ ofs = 0;
+ Base = Ext2_int_GetBlockAddr( disk, inode.i_block, block );
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * \fn int Ext2_MkNod(tVFS_Node *Parent, char *Name, Uint Flags)
+ * \brief Create a new node
+ */
+int Ext2_MkNod(tVFS_Node *Parent, char *Name, Uint Flags)
+{
+ return 0;
+}
+
+// ---- INTERNAL FUNCTIONS ----
+/**
+ * \fn vfs_node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID, char *Name)
+ * \brief Create a new VFS Node
+ */
+tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID, char *Name)
+{
+ tExt2_Inode inode;
+ tVFS_Node retNode;
+ tVFS_Node *tmpNode;
+
+ if( !Ext2_int_ReadInode(Disk, InodeID, &inode) )
+ return NULL;
+
+ if( (tmpNode = Inode_GetCache(Disk->CacheID, InodeID)) )
+ return tmpNode;
+
+
+ // Set identifiers
+ retNode.Inode = InodeID;
+ retNode.ImplPtr = Disk;
+
+ // Set file length
+ retNode.Size = inode.i_size;
+
+ // Set Access Permissions
+ retNode.UID = inode.i_uid;
+ retNode.GID = inode.i_gid;
+ retNode.NumACLs = 3;
+ retNode.ACLs = VFS_UnixToAcessACL(inode.i_mode & 0777, inode.i_uid, inode.i_gid);
+
+ // Set Function Pointers
+ retNode.Read = Ext2_Read;
+ retNode.Write = Ext2_Write;
+ retNode.Close = Ext2_CloseFile;
+
+ switch(inode.i_mode & EXT2_S_IFMT)
+ {
+ // Symbolic Link
+ case EXT2_S_IFLNK:
+ retNode.Flags = VFS_FFLAG_SYMLINK;
+ break;
+ // Regular File
+ case EXT2_S_IFREG:
+ retNode.Flags = 0;
+ retNode.Size |= (Uint64)inode.i_dir_acl << 32;
+ break;
+ // Directory
+ case EXT2_S_IFDIR:
+ retNode.ReadDir = Ext2_ReadDir;
+ retNode.FindDir = Ext2_FindDir;
+ retNode.MkNod = Ext2_MkNod;
+ //retNode.Relink = Ext2_Relink;
+ retNode.Flags = VFS_FFLAG_DIRECTORY;
+ break;
+ // Unknown, Write protect and hide it to be safe
+ default:
+ retNode.Flags = VFS_FFLAG_READONLY;//|VFS_FFLAG_HIDDEN;
+ break;
+ }
+
+ // Check if the file should be hidden
+ //if(Name[0] == '.') retNode.Flags |= VFS_FFLAG_HIDDEN;
+
+ // Set Timestamps
+ retNode.ATime = inode.i_atime * 1000;
+ retNode.MTime = inode.i_mtime * 1000;
+ retNode.CTime = inode.i_ctime * 1000;
+
+ // Save in node cache and return saved node
+ return Inode_CacheNode(Disk->CacheID, &retNode);
+}
--- /dev/null
+/*\r
+ * Acess OS\r
+ * Ext2 Driver Version 1\r
+ */\r
+/**\r
+ * \file fs/ext2.c\r
+ * \brief Second Extended Filesystem Driver\r
+ * \todo Implement file full write support\r
+ */\r
+#define DEBUG 1\r
+#define VERBOSE 0\r
+#include "ext2_common.h"\r
+#include <modules.h>\r
+\r
+// === PROTOTYPES ===\r
+ int Ext2_Install(char **Arguments);\r
+// Interface Functions\r
+tVFS_Node *Ext2_InitDevice(char *Device, char **Options);\r
+void Ext2_Unmount(tVFS_Node *Node);\r
+void Ext2_CloseFile(tVFS_Node *Node);\r
+// Internal Helpers\r
+ int Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode);\r
+Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum);\r
+Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent);\r
+void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk);\r
+\r
+// === SEMI-GLOBALS ===\r
+MODULE_DEFINE(0, 0x5B /*v0.90*/, FS_Ext2, Ext2_Install, NULL);\r
+tExt2_Disk gExt2_disks[6];\r
+ int giExt2_count = 0;\r
+tVFS_Driver gExt2_FSInfo = {\r
+ "ext2", 0, Ext2_InitDevice, Ext2_Unmount, NULL\r
+ };\r
+\r
+// === CODE ===\r
+/**\r
+ * \fn int Ext2_Install(char **Arguments)\r
+ * \brief Install the Ext2 Filesystem Driver\r
+ */\r
+int Ext2_Install(char **Arguments)\r
+{\r
+ VFS_AddDriver( &gExt2_FSInfo );\r
+ return MODULE_ERR_OK;\r
+}\r
+\r
+/**\r
+ \fn tVFS_Node *Ext2_InitDevice(char *Device, char **Options)\r
+ \brief Initializes a device to be read by by the driver\r
+ \param Device String - Device to read from\r
+ \param Options NULL Terminated array of option strings\r
+ \return Root Node\r
+*/\r
+tVFS_Node *Ext2_InitDevice(char *Device, char **Options)\r
+{\r
+ tExt2_Disk *disk;\r
+ int fd;\r
+ int groupCount;\r
+ tExt2_SuperBlock sb;\r
+ tExt2_Inode inode;\r
+ \r
+ ENTER("sDevice pOptions", Device, Options);\r
+ \r
+ // Open Disk\r
+ fd = VFS_Open(Device, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE); //Open Device\r
+ if(fd == -1) {\r
+ Log_Warning("EXT2", "Unable to open '%s'", Device);\r
+ LEAVE('n');\r
+ return NULL;\r
+ }\r
+ \r
+ // Read Superblock at offset 1024\r
+ VFS_ReadAt(fd, 1024, 1024, &sb); // Read Superblock\r
+ \r
+ // Sanity Check Magic value\r
+ if(sb.s_magic != 0xEF53) {\r
+ Log_Warning("EXT2", "Volume '%s' is not an EXT2 volume", Device);\r
+ VFS_Close(fd);\r
+ LEAVE('n');\r
+ return NULL;\r
+ }\r
+ \r
+ // Get Group count\r
+ groupCount = DivUp(sb.s_blocks_count, sb.s_blocks_per_group);\r
+ LOG("groupCount = %i", groupCount);\r
+ \r
+ // Allocate Disk Information\r
+ disk = malloc(sizeof(tExt2_Disk) + sizeof(tExt2_Group)*groupCount);\r
+ if(!disk) {\r
+ Log_Warning("EXT2", "Unable to allocate disk structure");\r
+ VFS_Close(fd);\r
+ LEAVE('n');\r
+ return NULL;\r
+ }\r
+ disk->FD = fd;\r
+ memcpy(&disk->SuperBlock, &sb, 1024);\r
+ disk->GroupCount = groupCount;\r
+ \r
+ // Get an inode cache handle\r
+ disk->CacheID = Inode_GetHandle();\r
+ \r
+ // Get Block Size\r
+ LOG("s_log_block_size = 0x%x", sb.s_log_block_size);\r
+ disk->BlockSize = 1024 << sb.s_log_block_size;\r
+ \r
+ // Read Group Information\r
+ VFS_ReadAt(\r
+ disk->FD,\r
+ sb.s_first_data_block * disk->BlockSize + 1024,\r
+ sizeof(tExt2_Group)*groupCount,\r
+ disk->Groups\r
+ );\r
+ \r
+ #if VERBOSE\r
+ LOG("Block Group 0");\r
+ LOG(".bg_block_bitmap = 0x%x", disk->Groups[0].bg_block_bitmap);\r
+ LOG(".bg_inode_bitmap = 0x%x", disk->Groups[0].bg_inode_bitmap);\r
+ LOG(".bg_inode_table = 0x%x", disk->Groups[0].bg_inode_table);\r
+ LOG("Block Group 1");\r
+ LOG(".bg_block_bitmap = 0x%x", disk->Groups[1].bg_block_bitmap);\r
+ LOG(".bg_inode_bitmap = 0x%x", disk->Groups[1].bg_inode_bitmap);\r
+ LOG(".bg_inode_table = 0x%x", disk->Groups[1].bg_inode_table);\r
+ #endif\r
+ \r
+ // Get root Inode\r
+ Ext2_int_ReadInode(disk, 2, &inode);\r
+ \r
+ // Create Root Node\r
+ memset(&disk->RootNode, 0, sizeof(tVFS_Node));\r
+ disk->RootNode.Inode = 2; // Root inode ID\r
+ disk->RootNode.ImplPtr = disk; // Save disk pointer\r
+ disk->RootNode.Size = -1; // Fill in later (on readdir)\r
+ disk->RootNode.Flags = VFS_FFLAG_DIRECTORY;\r
+ \r
+ disk->RootNode.ReadDir = Ext2_ReadDir;\r
+ disk->RootNode.FindDir = Ext2_FindDir;\r
+ //disk->RootNode.Relink = Ext2_Relink;\r
+ \r
+ // Complete root node\r
+ disk->RootNode.UID = inode.i_uid;\r
+ disk->RootNode.GID = inode.i_gid;\r
+ disk->RootNode.NumACLs = 1;\r
+ disk->RootNode.ACLs = &gVFS_ACL_EveryoneRW;\r
+ \r
+ #if DEBUG\r
+ LOG("inode.i_size = 0x%x", inode.i_size);\r
+ LOG("inode.i_block[0] = 0x%x", inode.i_block[0]);\r
+ #endif\r
+ \r
+ LEAVE('p', &disk->RootNode);\r
+ return &disk->RootNode;\r
+}\r
+\r
+/**\r
+ * \fn void Ext2_Unmount(tVFS_Node *Node)\r
+ * \brief Close a mounted device\r
+ */\r
+void Ext2_Unmount(tVFS_Node *Node)\r
+{\r
+ tExt2_Disk *disk = Node->ImplPtr;\r
+ \r
+ VFS_Close( disk->FD );\r
+ Inode_ClearCache( disk->CacheID );\r
+ memset(disk, 0, sizeof(tExt2_Disk)+disk->GroupCount*sizeof(tExt2_Group));\r
+ free(disk);\r
+}\r
+\r
+/**\r
+ * \fn void Ext2_CloseFile(tVFS_Node *Node)\r
+ * \brief Close a file (Remove it from the cache)\r
+ */\r
+void Ext2_CloseFile(tVFS_Node *Node)\r
+{\r
+ tExt2_Disk *disk = Node->ImplPtr;\r
+ Inode_UncacheNode(disk->CacheID, Node->Inode);\r
+ return ;\r
+}\r
+\r
+//==================================\r
+//= INTERNAL FUNCTIONS =\r
+//==================================\r
+/**\r
+ * \fn int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode)\r
+ * \brief Read an inode into memory\r
+ */\r
+int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode)\r
+{\r
+ int group, subId;\r
+ \r
+ ENTER("pDisk iInodeId pInode", Disk, InodeId, Inode);\r
+ \r
+ if(InodeId == 0) return 0;\r
+ \r
+ InodeId --; // Inodes are numbered starting at 1\r
+ \r
+ group = InodeId / Disk->SuperBlock.s_inodes_per_group;\r
+ subId = InodeId % Disk->SuperBlock.s_inodes_per_group;\r
+ \r
+ LOG("group=%i, subId = %i", group, subId);\r
+ \r
+ // Read Inode\r
+ VFS_ReadAt(Disk->FD,\r
+ Disk->Groups[group].bg_inode_table * Disk->BlockSize + sizeof(tExt2_Inode)*subId,\r
+ sizeof(tExt2_Inode),\r
+ Inode);\r
+ \r
+ LEAVE('i', 1);\r
+ return 1;\r
+}\r
+\r
+/**\r
+ * \brief Write a modified inode out to disk\r
+ */\r
+int Ext2_int_WriteInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode)\r
+{\r
+ int group, subId;\r
+ ENTER("pDisk iInodeId pInode", Disk, InodeId, Inode);\r
+ \r
+ if(InodeId == 0) {\r
+ LEAVE('i', 0);\r
+ return 0;\r
+ }\r
+ \r
+ InodeId --; // Inodes are numbered starting at 1\r
+ \r
+ group = InodeId / Disk->SuperBlock.s_inodes_per_group;\r
+ subId = InodeId % Disk->SuperBlock.s_inodes_per_group;\r
+ \r
+ LOG("group=%i, subId = %i", group, subId);\r
+ \r
+ // Write Inode\r
+ VFS_WriteAt(Disk->FD,\r
+ Disk->Groups[group].bg_inode_table * Disk->BlockSize + sizeof(tExt2_Inode)*subId,\r
+ sizeof(tExt2_Inode),\r
+ Inode\r
+ );\r
+ \r
+ LEAVE('i', 1);\r
+ return 1;\r
+}\r
+\r
+/**\r
+ * \fn Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum)\r
+ * \brief Get the address of a block from an inode's list\r
+ * \param Disk Disk information structure\r
+ * \param Blocks Pointer to an inode's block list\r
+ * \param BlockNum Block index in list\r
+ */\r
+Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum)\r
+{\r
+ Uint32 *iBlocks;\r
+ int dwPerBlock = Disk->BlockSize / 4;\r
+ \r
+ // Direct Blocks\r
+ if(BlockNum < 12)\r
+ return (Uint64)Blocks[BlockNum] * Disk->BlockSize;\r
+ \r
+ // Single Indirect Blocks\r
+ iBlocks = malloc( Disk->BlockSize );\r
+ VFS_ReadAt(Disk->FD, (Uint64)Blocks[12]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
+ \r
+ BlockNum -= 12;\r
+ if(BlockNum < dwPerBlock)\r
+ {\r
+ BlockNum = iBlocks[BlockNum];\r
+ free(iBlocks);\r
+ return (Uint64)BlockNum * Disk->BlockSize;\r
+ }\r
+ \r
+ BlockNum -= dwPerBlock;\r
+ // Double Indirect Blocks\r
+ if(BlockNum < dwPerBlock*dwPerBlock)\r
+ {\r
+ VFS_ReadAt(Disk->FD, (Uint64)Blocks[13]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
+ VFS_ReadAt(Disk->FD, (Uint64)iBlocks[BlockNum/dwPerBlock]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
+ BlockNum = iBlocks[BlockNum%dwPerBlock];\r
+ free(iBlocks);\r
+ return (Uint64)BlockNum * Disk->BlockSize;\r
+ }\r
+ \r
+ BlockNum -= dwPerBlock*dwPerBlock;\r
+ // Triple Indirect Blocks\r
+ VFS_ReadAt(Disk->FD, (Uint64)Blocks[14]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
+ VFS_ReadAt(Disk->FD, (Uint64)iBlocks[BlockNum/(dwPerBlock*dwPerBlock)]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
+ VFS_ReadAt(Disk->FD, (Uint64)iBlocks[(BlockNum/dwPerBlock)%dwPerBlock]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
+ BlockNum = iBlocks[BlockNum%dwPerBlock];\r
+ free(iBlocks);\r
+ return (Uint64)BlockNum * Disk->BlockSize;\r
+}\r
+\r
+/**\r
+ * \fn Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent)\r
+ * \brief Allocate an inode (from the current group preferably)\r
+ * \param Disk EXT2 Disk Information Structure\r
+ * \param Parent Inode ID of the parent (used to locate the child nearby)\r
+ */\r
+Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent)\r
+{\r
+// Uint block = (Parent - 1) / Disk->SuperBlock.s_inodes_per_group;\r
+ Log_Warning("EXT2", "Ext2_int_AllocateInode is unimplemented");\r
+ return 0;\r
+}\r
+\r
+/**\r
+ * \fn void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk)\r
+ * \brief Updates the superblock\r
+ */\r
+void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk)\r
+{\r
+ int bpg = Disk->SuperBlock.s_blocks_per_group;\r
+ int ngrp = Disk->SuperBlock.s_blocks_count / bpg;\r
+ int i;\r
+ \r
+ // Update Primary\r
+ VFS_WriteAt(Disk->FD, 1024, 1024, &Disk->SuperBlock);\r
+ \r
+ // Secondaries\r
+ // at Block Group 1, 3^n, 5^n, 7^n\r
+ \r
+ // 1\r
+ if(ngrp <= 1) return;\r
+ VFS_WriteAt(Disk->FD, 1*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock);\r
+ \r
+ // Powers of 3\r
+ for( i = 3; i < ngrp; i *= 3 )\r
+ VFS_WriteAt(Disk->FD, i*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock);\r
+ \r
+ // Powers of 5\r
+ for( i = 5; i < ngrp; i *= 5 )\r
+ VFS_WriteAt(Disk->FD, i*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock);\r
+ \r
+ // Powers of 7\r
+ for( i = 7; i < ngrp; i *= 7 )\r
+ VFS_WriteAt(Disk->FD, i*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock);\r
+}\r
--- /dev/null
+/*
+ * Acess OS
+ * Ext2 Driver Version 1
+ */
+/**
+ * \file ext2_common.h
+ * \brief Second Extended Filesystem Driver
+ */
+#ifndef _EXT2_COMMON_H
+#define _EXT2_COMMON_H
+#include <acess.h>
+#include <vfs.h>
+#include "ext2fs.h"
+
+#define EXT2_UPDATE_WRITEBACK 1
+
+// === STRUCTURES ===
+typedef struct {
+ int FD;
+ int CacheID;
+ tVFS_Node RootNode;
+
+ tExt2_SuperBlock SuperBlock;
+ int BlockSize;
+
+ int GroupCount;
+ tExt2_Group Groups[];
+} tExt2_Disk;
+
+// === FUNCTIONS ===
+// --- Common ---
+extern void Ext2_CloseFile(tVFS_Node *Node);
+extern Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum);
+extern void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk);
+extern int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode);
+extern int Ext2_int_WriteInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode);
+// --- Dir ---
+extern char *Ext2_ReadDir(tVFS_Node *Node, int Pos);
+extern tVFS_Node *Ext2_FindDir(tVFS_Node *Node, char *FileName);
+extern int Ext2_MkNod(tVFS_Node *Node, char *Name, Uint Flags);
+// --- Read ---
+extern Uint64 Ext2_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);
+// --- Write ---
+extern Uint64 Ext2_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);
+
+#endif
--- /dev/null
+/**\r
+ * Acess2\r
+ * \file ext2fs.h\r
+ * \brief EXT2 Filesystem Driver\r
+ */\r
+#ifndef _EXT2FS_H_\r
+#define _EXT2FS_H_\r
+\r
+/**\r
+ \name Inode Flag Values\r
+ \{\r
+*/\r
+#define EXT2_S_IFMT 0xF000 //!< Format Mask\r
+#define EXT2_S_IFSOCK 0xC000 //!< Socket\r
+#define EXT2_S_IFLNK 0xA000 //!< Symbolic Link\r
+#define EXT2_S_IFREG 0x8000 //!< Regular File\r
+#define EXT2_S_IFBLK 0x6000 //!< Block Device\r
+#define EXT2_S_IFDIR 0x4000 //!< Directory\r
+#define EXT2_S_IFCHR 0x2000 //!< Character Device\r
+#define EXT2_S_IFIFO 0x1000 //!< FIFO\r
+#define EXT2_S_ISUID 0x0800 //!< SUID\r
+#define EXT2_S_ISGID 0x0400 //!< SGID\r
+#define EXT2_S_ISVTX 0x0200 //!< sticky bit\r
+#define EXT2_S_IRWXU 0700 //!< user access rights mask\r
+#define EXT2_S_IRUSR 0400 //!< Owner Read\r
+#define EXT2_S_IWUSR 0200 //!< Owner Write\r
+#define EXT2_S_IXUSR 0100 //!< Owner Execute\r
+#define EXT2_S_IRWXG 0070 //!< Group Access rights mask\r
+#define EXT2_S_IRGRP 0040 //!< Group Read\r
+#define EXT2_S_IWGRP 0020 //!< Group Write\r
+#define EXT2_S_IXGRP 0010 //!< Group Execute\r
+#define EXT2_S_IRWXO 0007 //!< Global Access rights mask\r
+#define EXT2_S_IROTH 0004 //!< Global Read\r
+#define EXT2_S_IWOTH 0002 //!< Global Write\r
+#define EXT2_S_IXOTH 0001 //!< Global Execute\r
+//! \}\r
+\r
+#define EXT2_NAME_LEN 255 //!< Maximum Name Length\r
+\r
+// === TYPEDEFS ===\r
+typedef struct ext2_inode_s tExt2_Inode; //!< Inode Type\r
+typedef struct ext2_super_block_s tExt2_SuperBlock; //!< Superblock Type\r
+typedef struct ext2_group_desc_s tExt2_Group; //!< Group Descriptor Type\r
+typedef struct ext2_dir_entry_s tExt2_DirEnt; //!< Directory Entry Type\r
+\r
+// === STRUCTURES ===\r
+/**\r
+ * \brief EXT2 Superblock Structure\r
+ */\r
+struct ext2_super_block_s {\r
+ Uint32 s_inodes_count; //!< Inodes count\r
+ Uint32 s_blocks_count; //!< Blocks count\r
+ Uint32 s_r_blocks_count; //!< Reserved blocks count\r
+ Uint32 s_free_blocks_count; //!< Free blocks count\r
+ Uint32 s_free_inodes_count; //!< Free inodes count\r
+ Uint32 s_first_data_block; //!< First Data Block\r
+ Uint32 s_log_block_size; //!< Block size\r
+ Sint32 s_log_frag_size; //!< Fragment size\r
+ Uint32 s_blocks_per_group; //!< Number Blocks per group\r
+ Uint32 s_frags_per_group; //!< Number Fragments per group\r
+ Uint32 s_inodes_per_group; //!< Number Inodes per group\r
+ Uint32 s_mtime; //!< Mount time\r
+ Uint32 s_wtime; //!< Write time\r
+ Uint16 s_mnt_count; //!< Mount count\r
+ Sint16 s_max_mnt_count; //!< Maximal mount count\r
+ Uint16 s_magic; //!< Magic signature\r
+ Uint16 s_state; //!< File system state\r
+ Uint16 s_errors; //!< Behaviour when detecting errors\r
+ Uint16 s_pad; //!< Padding\r
+ Uint32 s_lastcheck; //!< time of last check\r
+ Uint32 s_checkinterval; //!< max. time between checks\r
+ Uint32 s_creator_os; //!< Formatting OS\r
+ Uint32 s_rev_level; //!< Revision level\r
+ Uint16 s_def_resuid; //!< Default uid for reserved blocks\r
+ Uint16 s_def_resgid; //!< Default gid for reserved blocks\r
+ Uint32 s_reserved[235]; //!< Padding to the end of the block\r
+};\r
+\r
+/**\r
+ * \struct ext2_inode_s\r
+ * \brief EXT2 Inode Definition\r
+ */\r
+struct ext2_inode_s {\r
+ Uint16 i_mode; //!< File mode\r
+ Uint16 i_uid; //!< Owner Uid\r
+ Uint32 i_size; //!< Size in bytes\r
+ Uint32 i_atime; //!< Access time\r
+ Uint32 i_ctime; //!< Creation time\r
+ Uint32 i_mtime; //!< Modification time\r
+ Uint32 i_dtime; //!< Deletion Time\r
+ Uint16 i_gid; //!< Group Id\r
+ Uint16 i_links_count; //!< Links count\r
+ Uint32 i_blocks; //!< Number of blocks allocated for the file\r
+ Uint32 i_flags; //!< File flags\r
+ union {\r
+ Uint32 linux_reserved1; //!< Linux: Reserved\r
+ Uint32 hurd_translator; //!< HURD: Translator\r
+ Uint32 masix_reserved1; //!< Masix: Reserved\r
+ } osd1; //!< OS dependent 1\r
+ Uint32 i_block[15]; //!< Pointers to blocks\r
+ Uint32 i_version; //!< File version (for NFS)\r
+ Uint32 i_file_acl; //!< File ACL\r
+ Uint32 i_dir_acl; //!< Directory ACL / Extended File Size\r
+ Uint32 i_faddr; //!< Fragment address\r
+ union {\r
+ struct {\r
+ Uint8 l_i_frag; //!< Fragment number\r
+ Uint8 l_i_fsize; //!< Fragment size\r
+ Uint16 i_pad1; //!< Padding\r
+ Uint32 l_i_reserved2[2]; //!< Reserved\r
+ } linux2;\r
+ struct {\r
+ Uint8 h_i_frag; //!< Fragment number\r
+ Uint8 h_i_fsize; //!< Fragment size\r
+ Uint16 h_i_mode_high; //!< Mode High Bits\r
+ Uint16 h_i_uid_high; //!< UID High Bits\r
+ Uint16 h_i_gid_high; //!< GID High Bits\r
+ Uint32 h_i_author; //!< Creator ID\r
+ } hurd2;\r
+ struct {\r
+ Uint8 m_i_frag; //!< Fragment number\r
+ Uint8 m_i_fsize; //!< Fragment size\r
+ Uint16 m_pad1; //!< Padding\r
+ Uint32 m_i_reserved2[2]; //!< reserved\r
+ } masix2;\r
+ } osd2; //!< OS dependent 2\r
+};\r
+\r
+/**\r
+ * \struct ext2_group_desc_s\r
+ * \brief EXT2 Group Descriptor\r
+ */\r
+struct ext2_group_desc_s {\r
+ Uint32 bg_block_bitmap; //!< Blocks bitmap block\r
+ Uint32 bg_inode_bitmap; //!< Inodes bitmap block\r
+ Uint32 bg_inode_table; //!< Inodes table block\r
+ Uint16 bg_free_blocks_count; //!< Free blocks count\r
+ Uint16 bg_free_inodes_count; //!< Free inodes count\r
+ Uint16 bg_used_dirs_count; //!< Directories count\r
+ Uint16 bg_pad; //!< Padding\r
+ Uint32 bg_reserved[3]; //!< Reserved\r
+};\r
+\r
+/**\r
+ * \brief EXT2 Directory Entry\r
+ * \note The name may take up less than 255 characters\r
+ */\r
+struct ext2_dir_entry_s {\r
+ Uint32 inode; //!< Inode number\r
+ Uint16 rec_len; //!< Directory entry length\r
+ Uint8 name_len; //!< Short Name Length\r
+ Uint8 type; //!< File Type\r
+ char name[]; //!< File name\r
+};\r
+\r
+#endif\r
--- /dev/null
+/*
+ * Acess OS
+ * Ext2 Driver Version 1
+ */
+/**
+ * \file read.c
+ * \brief Second Extended Filesystem Driver
+ * \todo Implement file full write support
+ */
+#define DEBUG 1
+#define VERBOSE 0
+#include "ext2_common.h"
+
+// === PROTOTYPES ===
+Uint64 Ext2_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);
+
+// === CODE ===
+/**
+ * \fn Uint64 Ext2_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \brief Read from a file
+ */
+Uint64 Ext2_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+ tExt2_Disk *disk = Node->ImplPtr;
+ tExt2_Inode inode;
+ Uint64 base;
+ Uint block;
+ Uint64 remLen;
+
+ ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
+
+ // Get Inode
+ Ext2_int_ReadInode(disk, Node->Inode, &inode);
+
+ // Sanity Checks
+ if(Offset >= inode.i_size) {
+ LEAVE('i', 0);
+ return 0;
+ }
+ if(Offset + Length > inode.i_size)
+ Length = inode.i_size - Offset;
+
+ block = Offset / disk->BlockSize;
+ Offset = Offset / disk->BlockSize;
+ base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
+ if(base == 0) {
+ Warning("[EXT2 ] NULL Block Detected in INode 0x%llx", Node->Inode);
+ LEAVE('i', 0);
+ return 0;
+ }
+
+ // Read only block
+ if(Length <= disk->BlockSize - Offset)
+ {
+ VFS_ReadAt( disk->FD, base+Offset, Length, Buffer);
+ LEAVE('X', Length);
+ return Length;
+ }
+
+ // Read first block
+ remLen = Length;
+ VFS_ReadAt( disk->FD, base + Offset, disk->BlockSize - Offset, Buffer);
+ remLen -= disk->BlockSize - Offset;
+ Buffer += disk->BlockSize - Offset;
+ block ++;
+
+ // Read middle blocks
+ while(remLen > disk->BlockSize)
+ {
+ base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
+ if(base == 0) {
+ Warning("[EXT2 ] NULL Block Detected in INode 0x%llx", Node->Inode);
+ LEAVE('i', 0);
+ return 0;
+ }
+ VFS_ReadAt( disk->FD, base, disk->BlockSize, Buffer);
+ Buffer += disk->BlockSize;
+ remLen -= disk->BlockSize;
+ block ++;
+ }
+
+ // Read last block
+ base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
+ VFS_ReadAt( disk->FD, base, remLen, Buffer);
+
+ LEAVE('X', Length);
+ return Length;
+}
--- /dev/null
+/*
+ * Acess OS
+ * Ext2 Driver Version 1
+ */
+/**
+ * \file write.c
+ * \brief Second Extended Filesystem Driver
+ * \todo Implement file full write support
+ */
+#define DEBUG 1
+#define VERBOSE 0
+#include "ext2_common.h"
+
+// === PROTOYPES ===
+Uint64 Ext2_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);
+Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock);
+void Ext2_int_DeallocateBlock(tExt2_Disk *Disk, Uint32 Block);
+ int Ext2_int_AppendBlock(tExt2_Disk *Disk, tExt2_Inode *Inode, Uint32 Block);
+
+// === CODE ===
+/**
+ * \fn Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \brief Write to a file
+ */
+Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+ tExt2_Disk *disk = Node->ImplPtr;
+ tExt2_Inode inode;
+ Uint64 base;
+ Uint64 retLen;
+ Uint block;
+ Uint64 allocSize;
+ int bNewBlocks = 0;
+
+ Debug_HexDump("Ext2_Write", Buffer, Length);
+
+ Ext2_int_ReadInode(disk, Node->Inode, &inode);
+
+ // Get the ammount of space already allocated
+ // - Round size up to block size
+ // - block size is a power of two, so this will work
+ allocSize = (inode.i_size + disk->BlockSize-1) & ~(disk->BlockSize-1);
+
+ // Are we writing to inside the allocated space?
+ if( Offset > allocSize ) return 0;
+
+ if( Offset < allocSize )
+ {
+ // Will we go out of it?
+ if(Offset + Length > allocSize) {
+ bNewBlocks = 1;
+ retLen = allocSize - Offset;
+ } else
+ retLen = Length;
+
+ // Within the allocated space
+ block = Offset / disk->BlockSize;
+ Offset %= disk->BlockSize;
+ base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
+
+ // Write only block (if only one)
+ if(Offset + retLen <= disk->BlockSize) {
+ VFS_WriteAt(disk->FD, base+Offset, retLen, Buffer);
+ if(!bNewBlocks) return Length;
+ goto addBlocks; // Ugh! A goto, but it seems unavoidable
+ }
+
+ // Write First Block
+ VFS_WriteAt(disk->FD, base+Offset, disk->BlockSize-Offset, Buffer);
+ Buffer += disk->BlockSize-Offset;
+ retLen -= disk->BlockSize-Offset;
+ block ++;
+
+ // Write middle blocks
+ while(retLen > disk->BlockSize)
+ {
+ base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
+ VFS_WriteAt(disk->FD, base, disk->BlockSize, Buffer);
+ Buffer += disk->BlockSize;
+ retLen -= disk->BlockSize;
+ block ++;
+ }
+
+ // Write last block
+ base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
+ VFS_WriteAt(disk->FD, base, retLen, Buffer);
+ if(!bNewBlocks) return Length; // Writing in only allocated space
+ }
+ else
+ base = Ext2_int_GetBlockAddr(disk, inode.i_block, allocSize/disk->BlockSize-1);
+
+addBlocks:
+ Log_Notice("EXT2", "File extending is untested");
+
+ // Allocate blocks and copy data to them
+ retLen = Length - (allocSize-Offset);
+ while( retLen > disk->BlockSize )
+ {
+ // Allocate a block
+ block = Ext2_int_AllocateBlock(disk, base/disk->BlockSize);
+ if(!block) return Length - retLen;
+ // Add it to this inode
+ if( !Ext2_int_AppendBlock(disk, &inode, block) ) {
+ Ext2_int_DeallocateBlock(disk, block);
+ goto ret;
+ }
+ // Copy data to the node
+ base = block * disk->BlockSize;
+ VFS_WriteAt(disk->FD, base, disk->BlockSize, Buffer);
+ // Update pointer and size remaining
+ inode.i_size += disk->BlockSize;
+ Buffer += disk->BlockSize;
+ retLen -= disk->BlockSize;
+ }
+ // Last block :D
+ block = Ext2_int_AllocateBlock(disk, base/disk->BlockSize);
+ if(!block) goto ret;
+ if( !Ext2_int_AppendBlock(disk, &inode, block) ) {
+ Ext2_int_DeallocateBlock(disk, block);
+ goto ret;
+ }
+ base = block * disk->BlockSize;
+ VFS_WriteAt(disk->FD, base, retLen, Buffer);
+ inode.i_size += retLen;
+ retLen = 0;
+
+ret: // Makes sure the changes to the inode are committed
+ Ext2_int_WriteInode(disk, Node->Inode, &inode);
+ return Length - retLen;
+}
+
+/**
+ * \fn Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock)
+ * \brief Allocate a block from the best possible location
+ * \param Disk EXT2 Disk Information Structure
+ * \param PrevBlock Previous block ID in the file
+ */
+Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock)
+{
+ int bpg = Disk->SuperBlock.s_blocks_per_group;
+ Uint blockgroup = PrevBlock / bpg;
+ Uint bitmap[Disk->BlockSize/sizeof(Uint)];
+ Uint bitsperblock = 8*Disk->BlockSize;
+ int i, j = 0;
+ Uint block;
+
+ // Are there any free blocks?
+ if(Disk->SuperBlock.s_free_blocks_count == 0) return 0;
+
+ if(Disk->Groups[blockgroup].bg_free_blocks_count > 0)
+ {
+ // Search block group's bitmap
+ for(i = 0; i < bpg; i++)
+ {
+ // Get the block in the bitmap block
+ j = i & (bitsperblock-1);
+
+ // Read in if needed
+ if(j == 0) {
+ VFS_ReadAt(
+ Disk->FD,
+ (Uint64)Disk->Groups[blockgroup].bg_block_bitmap + i / bitsperblock,
+ Disk->BlockSize,
+ bitmap
+ );
+ }
+
+ // Fast Check
+ if( bitmap[j/32] == -1 ) {
+ j = (j + 31) & ~31;
+ continue;
+ }
+
+ // Is the bit set?
+ if( bitmap[j/32] & (1 << (j%32)) )
+ continue;
+
+ // Ooh! We found one
+ break;
+ }
+ if( i < bpg ) {
+ Warning("[EXT2 ] Inconsistency detected, Group Free Block count is non-zero when no free blocks exist");
+ goto checkAll; // Search the entire filesystem for a free block
+ // Goto needed for neatness
+ }
+
+ // Mark as used
+ bitmap[j/32] |= (1 << (j%32));
+ VFS_WriteAt(
+ Disk->FD,
+ (Uint64)Disk->Groups[blockgroup].bg_block_bitmap + i / bitsperblock,
+ Disk->BlockSize,
+ bitmap
+ );
+ block = i;
+ Disk->Groups[blockgroup].bg_free_blocks_count --;
+ #if EXT2_UPDATE_WRITEBACK
+ //Ext2_int_UpdateBlockGroup(Disk, blockgroup);
+ #endif
+ }
+ else
+ {
+ checkAll:
+ Log_Warning("EXT2", "TODO - Implement using blocks outside the current block group");
+ return 0;
+ }
+
+ // Reduce global count
+ Disk->SuperBlock.s_free_blocks_count --;
+ #if EXT2_UPDATE_WRITEBACK
+ Ext2_int_UpdateSuperblock(Disk);
+ #endif
+
+ return block;
+}
+
+/**
+ * \brief Deallocates a block
+ */
+void Ext2_int_DeallocateBlock(tExt2_Disk *Disk, Uint32 Block)
+{
+}
+
+/**
+ * \brief Append a block to an inode
+ */
+int Ext2_int_AppendBlock(tExt2_Disk *Disk, tExt2_Inode *Inode, Uint32 Block)
+{
+ int nBlocks;
+ int dwPerBlock = Disk->BlockSize / 4;
+ Uint32 *blocks;
+ Uint32 id1, id2;
+
+ nBlocks = (Inode->i_size + Disk->BlockSize - 1) / Disk->BlockSize;
+
+ // Direct Blocks
+ if( nBlocks < 12 ) {
+ Inode->i_block[nBlocks] = Block;
+ return 0;
+ }
+
+ blocks = malloc( Disk->BlockSize );
+ if(!blocks) return 1;
+
+ nBlocks -= 12;
+ // Single Indirect
+ if( nBlocks < dwPerBlock)
+ {
+ // Allocate/Get Indirect block
+ if( nBlocks == 0 ) {
+ Inode->i_block[12] = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]);
+ if( !Inode->i_block[12] ) {
+ free(blocks);
+ return 1;
+ }
+ memset(blocks, 0, Disk->BlockSize);
+ }
+ else
+ VFS_ReadAt(Disk->FD, Inode->i_block[12]*Disk->BlockSize, Disk->BlockSize, blocks);
+
+ blocks[nBlocks] = Block;
+
+ VFS_WriteAt(Disk->FD, Inode->i_block[12]*Disk->BlockSize, Disk->BlockSize, blocks);
+ free(blocks);
+ return 0;
+ }
+
+ nBlocks += dwPerBlock;
+ // Double Indirect
+ if( nBlocks < dwPerBlock*dwPerBlock )
+ {
+ // Allocate/Get Indirect block
+ if( nBlocks == 0 ) {
+ Inode->i_block[13] = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]);
+ if( !Inode->i_block[13] ) {
+ free(blocks);
+ return 1;
+ }
+ memset(blocks, 0, Disk->BlockSize);
+ }
+ else
+ VFS_ReadAt(Disk->FD, Inode->i_block[13]*Disk->BlockSize, Disk->BlockSize, blocks);
+
+ // Allocate / Get Indirect lvl2 Block
+ if( nBlocks % dwPerBlock == 0 ) {
+ id1 = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]);
+ if( !id1 ) {
+ free(blocks);
+ return 1;
+ }
+ blocks[nBlocks/dwPerBlock] = id1;
+ // Write back indirect 1 block
+ VFS_WriteAt(Disk->FD, Inode->i_block[13]*Disk->BlockSize, Disk->BlockSize, blocks);
+ memset(blocks, 0, Disk->BlockSize);
+ }
+ else {
+ id1 = blocks[nBlocks / dwPerBlock];
+ VFS_ReadAt(Disk->FD, id1*Disk->BlockSize, Disk->BlockSize, blocks);
+ }
+
+ blocks[nBlocks % dwPerBlock] = Block;
+
+ VFS_WriteAt(Disk->FD, id1*Disk->BlockSize, Disk->BlockSize, blocks);
+ free(blocks);
+ return 0;
+ }
+
+ nBlocks -= dwPerBlock*dwPerBlock;
+ // Triple Indirect
+ if( nBlocks < dwPerBlock*dwPerBlock*dwPerBlock )
+ {
+ // Allocate/Get Indirect block
+ if( nBlocks == 0 ) {
+ Inode->i_block[14] = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]);
+ if( !Inode->i_block[14] ) {
+ free(blocks);
+ return 1;
+ }
+ memset(blocks, 0, Disk->BlockSize);
+ }
+ else
+ VFS_ReadAt(Disk->FD, Inode->i_block[14]*Disk->BlockSize, Disk->BlockSize, blocks);
+
+ // Allocate / Get Indirect lvl2 Block
+ if( (nBlocks/dwPerBlock) % dwPerBlock == 0 && nBlocks % dwPerBlock == 0 )
+ {
+ id1 = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]);
+ if( !id1 ) {
+ free(blocks);
+ return 1;
+ }
+ blocks[nBlocks/dwPerBlock] = id1;
+ // Write back indirect 1 block
+ VFS_WriteAt(Disk->FD, Inode->i_block[14]*Disk->BlockSize, Disk->BlockSize, blocks);
+ memset(blocks, 0, Disk->BlockSize);
+ }
+ else {
+ id1 = blocks[nBlocks / (dwPerBlock*dwPerBlock)];
+ VFS_ReadAt(Disk->FD, id1*Disk->BlockSize, Disk->BlockSize, blocks);
+ }
+
+ // Allocate / Get Indirect Level 3 Block
+ if( nBlocks % dwPerBlock == 0 ) {
+ id2 = Ext2_int_AllocateBlock(Disk, id1);
+ if( !id2 ) {
+ free(blocks);
+ return 1;
+ }
+ blocks[(nBlocks/dwPerBlock)%dwPerBlock] = id2;
+ // Write back indirect 1 block
+ VFS_WriteAt(Disk->FD, id1*Disk->BlockSize, Disk->BlockSize, blocks);
+ memset(blocks, 0, Disk->BlockSize);
+ }
+ else {
+ id2 = blocks[(nBlocks/dwPerBlock)%dwPerBlock];
+ VFS_ReadAt(Disk->FD, id2*Disk->BlockSize, Disk->BlockSize, blocks);
+ }
+
+ blocks[nBlocks % dwPerBlock] = Block;
+
+ VFS_WriteAt(Disk->FD, id2*Disk->BlockSize, Disk->BlockSize, blocks);
+ free(blocks);
+ return 0;
+ }
+
+ Warning("[EXT2 ] Inode %i cannot have a block appended to it, all indirects used");
+ free(blocks);
+ return 1;
+}
--- /dev/null
+#
+#
+
+OBJ = fat.o
+NAME = FAT
+
+-include ../Makefile.tpl
--- /dev/null
+/*\r
+ * Acess 2\r
+ * FAT12/16/32 Driver Version (Incl LFN)\r
+ * \r
+ * NOTE: This driver will only support _reading_ long file names, not\r
+ * writing. I don't even know why i'm adding write-support. FAT sucks.\r
+ * \r
+ * Known Bugs:\r
+ * - LFN Is buggy in FAT_ReadDir\r
+ */\r
+/**\r
+ * \todo Implement changing of the parent directory when a file is written to\r
+ * \todo Implement file creation / deletion\r
+ */\r
+#define DEBUG 1\r
+#define VERBOSE 1\r
+\r
+#define CACHE_FAT 1 //!< Caches the FAT in memory\r
+#define USE_LFN 0 //!< Enables the use of Long File Names\r
+#define SUPPORT_WRITE 0\r
+\r
+#include <acess.h>\r
+#include <modules.h>\r
+#include <vfs.h>\r
+#include "fs_fat.h"\r
+\r
+#define FAT_FLAG_DIRTY 0x10000\r
+#define FAT_FLAG_DELETE 0x20000\r
+\r
+// === TYPES ===\r
+#if USE_LFN\r
+typedef struct s_lfncache\r
+{\r
+ Uint Inode;\r
+ tFAT_VolInfo *Disk;\r
+ int id;\r
+ char Name[256];\r
+ struct s_lfncache *Next;\r
+} t_lfncache;\r
+#endif\r
+\r
+// === PROTOTYPES ===\r
+ int FAT_Install(char **Arguments);\r
+tVFS_Node *FAT_InitDevice(char *device, char **options);\r
+void FAT_Unmount(tVFS_Node *Node);\r
+\r
+Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 Cluster);\r
+Uint32 FAT_int_AllocateCluster(tFAT_VolInfo *Disk, Uint32 Previous);\r
+\r
+void FAT_int_ReadCluster(tFAT_VolInfo *Disk, Uint32 Cluster, int Length, void *Buffer);\r
+Uint64 FAT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);\r
+#if SUPPORT_WRITE\r
+void FAT_int_WriteCluster(tFAT_VolInfo *Disk, Uint32 Cluster, void *Buffer);\r
+Uint64 FAT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);\r
+#endif\r
+\r
+char *FAT_ReadDir(tVFS_Node *Node, int ID);\r
+tVFS_Node *FAT_FindDir(tVFS_Node *Node, char *Name);\r
+ int FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags);\r
+ int FAT_Relink(tVFS_Node *node, char *OldName, char *NewName);\r
+void FAT_CloseFile(tVFS_Node *node);\r
+\r
+// === Options ===\r
+ int giFAT_MaxCachedClusters = 1024*512/4;\r
+\r
+// === SEMI-GLOBALS ===\r
+MODULE_DEFINE(0, (0<<8)|50 /*v0.50*/, VFAT, FAT_Install, NULL, NULL);\r
+tFAT_VolInfo gFAT_Disks[8];\r
+ int giFAT_PartCount = 0;\r
+#if USE_LFN\r
+t_lfncache *fat_lfncache;\r
+#endif\r
+tVFS_Driver gFAT_FSInfo = {"fat", 0, FAT_InitDevice, FAT_Unmount, NULL};\r
+\r
+// === CODE ===\r
+/**\r
+ * \fn int FAT_Install(char **Arguments)\r
+ * \brief \r
+ */\r
+int FAT_Install(char **Arguments)\r
+{\r
+ VFS_AddDriver( &gFAT_FSInfo );\r
+ return MODULE_ERR_OK;\r
+}\r
+\r
+/**\r
+ * \fn tVFS_Node *FAT_InitDevice(char *Device, char **Options)\r
+ * \brief Reads the boot sector of a disk and prepares the structures for it\r
+ */\r
+tVFS_Node *FAT_InitDevice(char *Device, char **Options)\r
+{\r
+ fat_bootsect *bs;\r
+ int i;\r
+ Uint32 FATSz, RootDirSectors, TotSec;\r
+ tVFS_Node *node = NULL;\r
+ tFAT_VolInfo *diskInfo = &gFAT_Disks[giFAT_PartCount];\r
+ \r
+ // Temporary Pointer\r
+ bs = &diskInfo->bootsect;\r
+ \r
+ //Open device and read boot sector\r
+ diskInfo->fileHandle = VFS_Open(Device, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE);\r
+ if(diskInfo->fileHandle == -1) {\r
+ Log_Notice("FAT", "Unable to open device '%s'", Device);\r
+ return NULL;\r
+ }\r
+ \r
+ VFS_ReadAt(diskInfo->fileHandle, 0, 512, bs);\r
+ \r
+ if(bs->bps == 0 || bs->spc == 0) {\r
+ Log_Notice("FAT", "Error in FAT Boot Sector");\r
+ return NULL;\r
+ }\r
+ \r
+ // FAT Type Determining\r
+ // - From Microsoft FAT Specifcation\r
+ RootDirSectors = ((bs->files_in_root*32) + (bs->bps - 1)) / bs->bps;\r
+ \r
+ if(bs->fatSz16 != 0) FATSz = bs->fatSz16;\r
+ else FATSz = bs->spec.fat32.fatSz32;\r
+ \r
+ if(bs->totalSect16 != 0) TotSec = bs->totalSect16;\r
+ else TotSec = bs->totalSect32;\r
+ \r
+ diskInfo->ClusterCount = (TotSec - (bs->resvSectCount + (bs->fatCount * FATSz) + RootDirSectors)) / bs->spc;\r
+ \r
+ if(diskInfo->ClusterCount < 4085)\r
+ diskInfo->type = FAT12;\r
+ else if(diskInfo->ClusterCount < 65525)\r
+ diskInfo->type = FAT16;\r
+ else\r
+ diskInfo->type = FAT32;\r
+ \r
+ #if VERBOSE\r
+ {\r
+ char *sFatType, *sSize;\r
+ Uint iSize = diskInfo->ClusterCount * bs->spc * bs->bps / 1024;\r
+ \r
+ switch(diskInfo->type)\r
+ {\r
+ case FAT12: sFatType = "FAT12"; break;\r
+ case FAT16: sFatType = "FAT16"; break;\r
+ case FAT32: sFatType = "FAT32"; break;\r
+ default: sFatType = "UNKNOWN"; break;\r
+ }\r
+ if(iSize <= 2*1024) {\r
+ sSize = "KiB";\r
+ }\r
+ else if(iSize <= 2*1024*1024) {\r
+ sSize = "MiB";\r
+ iSize >>= 10;\r
+ }\r
+ else {\r
+ sSize = "GiB";\r
+ iSize >>= 20;\r
+ }\r
+ Log_Notice("FAT", "'%s' %s, %i %s", Device, sFatType, iSize, sSize);\r
+ }\r
+ #endif\r
+ \r
+ // Get Name\r
+ if(diskInfo->type == FAT32) {\r
+ for(i=0;i<11;i++)\r
+ diskInfo->name[i] = (bs->spec.fat32.label[i] == ' ' ? '\0' : bs->spec.fat32.label[i]);\r
+ }\r
+ else {\r
+ for(i=0;i<11;i++)\r
+ diskInfo->name[i] = (bs->spec.fat16.label[i] == ' ' ? '\0' : bs->spec.fat16.label[i]);\r
+ }\r
+ diskInfo->name[11] = '\0';\r
+ \r
+ // Compute Root directory offset\r
+ if(diskInfo->type == FAT32)\r
+ diskInfo->rootOffset = bs->spec.fat32.rootClust;\r
+ else\r
+ diskInfo->rootOffset = (FATSz * bs->fatCount) / bs->spc;\r
+ \r
+ diskInfo->firstDataSect = bs->resvSectCount + (bs->fatCount * FATSz) + RootDirSectors;\r
+ \r
+ //Allow for Caching the FAT\r
+ #if CACHE_FAT\r
+ if( diskInfo->ClusterCount <= giFAT_MaxCachedClusters )\r
+ {\r
+ Uint32 Ofs;\r
+ diskInfo->FATCache = (Uint32*)malloc(sizeof(Uint32)*diskInfo->ClusterCount);\r
+ if(diskInfo->FATCache == NULL) {\r
+ Log_Warning("FAT", "Heap Exhausted");\r
+ return NULL;\r
+ }\r
+ Ofs = bs->resvSectCount*512;\r
+ if(diskInfo->type == FAT12)\r
+ {\r
+ Uint32 val;\r
+ int j;\r
+ char buf[1536];\r
+ for(i = 0; i < diskInfo->ClusterCount/2; i++) {\r
+ j = i & 511; //%512\r
+ if( j == 0 ) {\r
+ VFS_ReadAt(diskInfo->fileHandle, Ofs, 3*512, buf);\r
+ Ofs += 3*512;\r
+ }\r
+ val = *((int*)(buf+j*3));\r
+ diskInfo->FATCache[i*2] = val & 0xFFF;\r
+ diskInfo->FATCache[i*2+1] = (val>>12) & 0xFFF;\r
+ }\r
+ }\r
+ else if(diskInfo->type == FAT16)\r
+ {\r
+ Uint16 buf[256];\r
+ for(i=0;i<diskInfo->ClusterCount;i++) {\r
+ if( (i & 255) == 0 ) {\r
+ VFS_ReadAt(diskInfo->fileHandle, Ofs, 512, buf);\r
+ Ofs += 512;\r
+ }\r
+ diskInfo->FATCache[i] = buf[i&255];\r
+ }\r
+ }\r
+ else if(diskInfo->type == FAT32)\r
+ {\r
+ Uint32 buf[128];\r
+ for(i=0;i<diskInfo->ClusterCount;i++) {\r
+ if( (i & 127) == 0 ) {\r
+ VFS_ReadAt(diskInfo->fileHandle, Ofs, 512, buf);\r
+ Ofs += 512;\r
+ }\r
+ diskInfo->FATCache[i] = buf[i&127];\r
+ }\r
+ }\r
+ LOG("FAT Fully Cached");\r
+ }\r
+ #endif /*CACHE_FAT*/\r
+ \r
+ diskInfo->BytesPerCluster = bs->spc * bs->bps;\r
+ \r
+ // Initalise inode cache for filesystem\r
+ diskInfo->inodeHandle = Inode_GetHandle();\r
+ LOG("Inode Cache handle is %i", diskInfo->inodeHandle);\r
+ \r
+ // == VFS Interface\r
+ node = &diskInfo->rootNode;\r
+ //node->Size = bs->files_in_root;\r
+ node->Size = -1;\r
+ node->Inode = diskInfo->rootOffset; // 0:31 - Cluster, 32:63 - Parent Directory Cluster\r
+ node->ImplPtr = diskInfo; // Disk info pointer\r
+ node->ImplInt = 0; // 0:15 - Directory Index, 16: Dirty Flag, 17: Deletion Flag\r
+ \r
+ node->ReferenceCount = 1;\r
+ \r
+ node->UID = 0; node->GID = 0;\r
+ node->NumACLs = 1;\r
+ node->ACLs = &gVFS_ACL_EveryoneRWX;\r
+ node->Flags = VFS_FFLAG_DIRECTORY;\r
+ node->CTime = node->MTime = node->ATime = now();\r
+ \r
+ node->Read = node->Write = NULL;\r
+ node->ReadDir = FAT_ReadDir;\r
+ node->FindDir = FAT_FindDir;\r
+ #if SUPPORT_WRITE\r
+ node->Relink = FAT_Relink;\r
+ node->MkNod = FAT_Mknod;\r
+ #else\r
+ node->Relink = NULL;\r
+ node->MkNod = NULL;\r
+ #endif\r
+ //node->Close = FAT_Unmount;\r
+ \r
+ giFAT_PartCount ++;\r
+ return node;\r
+}\r
+\r
+/**\r
+ * \brief Closes a mount and marks it as free\r
+ * \param Node Mount Root\r
+ * \r
+ * \todo Remove FAT Cache\r
+ * \todo Clear LFN Cache\r
+ * \todo Check that all files are closed and flushed\r
+ */\r
+void FAT_Unmount(tVFS_Node *Node)\r
+{\r
+ tFAT_VolInfo *disk = Node->ImplPtr;\r
+ \r
+ // Close Disk Handle\r
+ VFS_Close( disk->fileHandle );\r
+ // Clear Node Cache\r
+ Inode_ClearCache(disk->inodeHandle);\r
+ // Mark as unused\r
+ disk->fileHandle = -2;\r
+ return;\r
+}\r
+\r
+/**\r
+ * \brief Converts an offset in a file into a disk address\r
+ * \param Node File (or directory) node\r
+ * \param Offset Offset in the file\r
+ * \param Addr Return Address\r
+ * \param Cluster Set to the current cluster (or the last one if \a Offset\r
+ * is past EOC) - Not touched if the node is the root\r
+ * directory.\r
+ * \return Zero on success, non-zero on error\r
+ */\r
+int FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint32 *Cluster)\r
+{\r
+ Uint32 cluster;\r
+ Uint64 addr;\r
+ int skip;\r
+ tFAT_VolInfo *disk = Node->ImplPtr;\r
+ \r
+ ENTER("pNode XOffset", Node, Offset);\r
+ \r
+ cluster = Node->Inode & 0xFFFFFFFF; // Cluster ID\r
+ LOG("cluster = %08x", cluster);\r
+ \r
+ // Do Cluster Skip\r
+ // - Pre FAT32 had a reserved area for the root.\r
+ if( disk->type == FAT32 || cluster != disk->rootOffset )\r
+ {\r
+ skip = Offset / disk->BytesPerCluster;\r
+ LOG("skip = %i", skip);\r
+ // Skip previous clusters\r
+ for(; skip-- ; )\r
+ {\r
+ if(Cluster) *Cluster = cluster;\r
+ cluster = FAT_int_GetFatValue(disk, cluster);\r
+ // Check for end of cluster chain\r
+ if(cluster == -1) { LEAVE('i', 1); return 1;}\r
+ }\r
+ if(Cluster) *Cluster = cluster;\r
+ }\r
+ \r
+ // Bounds Checking (Used to spot corruption)\r
+ if(cluster > disk->ClusterCount + 2)\r
+ {\r
+ Log_Warning("FAT", "Cluster ID is over cluster count (0x%x>0x%x)",\r
+ cluster, disk->ClusterCount+2);\r
+ LEAVE('i', 1);\r
+ return 1;\r
+ }\r
+ \r
+ // Compute Offsets\r
+ // - Pre FAT32 cluster base (in sectors)\r
+ if( cluster == disk->rootOffset && disk->type != FAT32 ) {\r
+ addr = disk->bootsect.resvSectCount * disk->bootsect.bps;\r
+ addr += cluster * disk->BytesPerCluster;\r
+ }\r
+ else {\r
+ addr = disk->firstDataSect * disk->bootsect.bps;\r
+ addr += (cluster - 2) * disk->BytesPerCluster;\r
+ }\r
+ addr += Offset % disk->BytesPerCluster;\r
+ \r
+ LOG("addr = 0x%08x", addr);\r
+ *Addr = addr;\r
+ LEAVE('i', 0);\r
+ return 0;\r
+}\r
+\r
+/*\r
+ * ====================\r
+ * FAT Manipulation\r
+ * ====================\r
+ */\r
+/**\r
+ * \fn Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster)\r
+ * \brief Fetches a value from the FAT\r
+ */\r
+Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster)\r
+{\r
+ Uint32 val = 0;\r
+ Uint32 ofs;\r
+ ENTER("pDisk xCluster", Disk, cluster);\r
+ LOCK( &Disk->lFAT );\r
+ #if CACHE_FAT\r
+ if( Disk->ClusterCount <= giFAT_MaxCachedClusters )\r
+ {\r
+ val = Disk->FATCache[cluster];\r
+ if(Disk->type == FAT12 && val == EOC_FAT12) val = -1;\r
+ if(Disk->type == FAT16 && val == EOC_FAT16) val = -1;\r
+ if(Disk->type == FAT32 && val == EOC_FAT32) val = -1;\r
+ }\r
+ else\r
+ {\r
+ #endif\r
+ ofs = Disk->bootsect.resvSectCount*512;\r
+ if(Disk->type == FAT12) {\r
+ VFS_ReadAt(Disk->fileHandle, ofs+(cluster>>1)*3, 3, &val);\r
+ val = (cluster&1 ? val&0xFFF : val>>12);\r
+ if(val == EOC_FAT12) val = -1;\r
+ } else if(Disk->type == FAT16) {\r
+ VFS_ReadAt(Disk->fileHandle, ofs+cluster*2, 2, &val);\r
+ if(val == EOC_FAT16) val = -1;\r
+ } else {\r
+ VFS_ReadAt(Disk->fileHandle, ofs+cluster*4, 4, &val);\r
+ if(val == EOC_FAT32) val = -1;\r
+ }\r
+ #if CACHE_FAT\r
+ }\r
+ #endif /*CACHE_FAT*/\r
+ RELEASE( &Disk->lFAT );\r
+ LEAVE('x', val);\r
+ return val;\r
+}\r
+\r
+#if SUPPORT_WRITE\r
+/**\r
+ * \brief Allocate a new cluster\r
+ */\r
+Uint32 FAT_int_AllocateCluster(tFAT_VolInfo *Disk, Uint32 Previous)\r
+{\r
+ Uint32 ret = Previous;\r
+ #if CACHE_FAT\r
+ if( Disk->ClusterCount <= giFAT_MaxCachedClusters )\r
+ {\r
+ Uint32 eoc;\r
+ \r
+ LOCK(Disk->lFAT);\r
+ for(ret = Previous; ret < Disk->ClusterCount; ret++)\r
+ {\r
+ if(Disk->FATCache[ret] == 0)\r
+ goto append;\r
+ }\r
+ for(ret = 0; ret < Previous; ret++)\r
+ {\r
+ if(Disk->FATCache[ret] == 0)\r
+ goto append;\r
+ }\r
+ \r
+ RELEASE(Disk->lFAT);\r
+ return 0;\r
+ \r
+ append:\r
+ switch(Disk->type)\r
+ {\r
+ case FAT12: eoc = EOC_FAT12; break;\r
+ case FAT16: eoc = EOC_FAT16; break;\r
+ case FAT32: eoc = EOC_FAT32; break;\r
+ default: return 0;\r
+ }\r
+ \r
+ Disk->FATCache[ret] = eoc;\r
+ Disk->FATCache[Previous] = ret;\r
+ \r
+ RELEASE(Disk->lFAT);\r
+ return ret;\r
+ }\r
+ else\r
+ {\r
+ #endif\r
+ Uint32 val;\r
+ Uint32 ofs = Disk->bootsect.resvSectCount*512;\r
+ Log_Warning("FAT", "TODO: Implement cluster allocation with non cached FAT");\r
+ return 0;\r
+ \r
+ switch(Disk->type)\r
+ {\r
+ case FAT12:\r
+ VFS_ReadAt(Disk->fileHandle, ofs+(Previous>>1)*3, 3, &val);\r
+ if( Previous & 1 ) {\r
+ val &= 0xFFF000;\r
+ val |= ret;\r
+ }\r
+ else {\r
+ val &= 0xFFF;\r
+ val |= ret<<12;\r
+ }\r
+ VFS_WriteAt(Disk->fileHandle, ofs+(Previous>>1)*3, 3, &val);\r
+ \r
+ VFS_ReadAt(Disk->fileHandle, ofs+(ret>>1)*3, 3, &val);\r
+ if( Cluster & 1 ) {\r
+ val &= 0xFFF000;\r
+ val |= eoc;\r
+ }\r
+ else {\r
+ val &= 0x000FFF;\r
+ val |= eoc<<12;\r
+ }\r
+ VFS_WriteAt(Disk->fileHandle, ofs+(ret>>1)*3, 3, &val);\r
+ break;\r
+ case FAT16:\r
+ VFS_ReadAt(Disk->fileHandle, ofs+Previous*2, 2, &ret);\r
+ VFS_WriteAt(Disk->fileHandle, ofs+ret*2, 2, &eoc);\r
+ break;\r
+ case FAT32:\r
+ VFS_ReadAt(Disk->fileHandle, ofs+Previous*4, 4, &ret);\r
+ VFS_WriteAt(Disk->fileHandle, ofs+ret*4, 4, &eoc);\r
+ break;\r
+ }\r
+ return ret;\r
+ #if CACHE_FAT\r
+ }\r
+ #endif\r
+}\r
+\r
+/**\r
+ * \brief Free's a cluster\r
+ * \return The original contents of the cluster\r
+ */\r
+Uint32 FAT_int_FreeCluster(tFAT_VolInfo *Disk, Uint32 Cluster)\r
+{\r
+ Uint32 ret;\r
+ #if CACHE_FAT\r
+ if( Disk->ClusterCount <= giFAT_MaxCachedClusters )\r
+ {\r
+ LOCK(Disk->lFAT);\r
+ \r
+ ret = Disk->FATCache[Cluster];\r
+ Disk->FATCache[Cluster] = 0;\r
+ \r
+ RELEASE(Disk->lFAT);\r
+ }\r
+ else\r
+ {\r
+ #endif\r
+ Uint32 val;\r
+ Uint32 ofs = Disk->bootsect.resvSectCount*512;\r
+ LOCK(Disk->lFAT);\r
+ switch(Disk->type)\r
+ {\r
+ case FAT12:\r
+ VFS_ReadAt(Disk->fileHandle, ofs+(Cluster>>1)*3, 3, &val);\r
+ if( Cluster & 1 ) {\r
+ ret = val & 0xFFF0000;\r
+ val &= 0xFFF;\r
+ }\r
+ else {\r
+ ret = val & 0xFFF;\r
+ val &= 0xFFF000;\r
+ }\r
+ VFS_WriteAt(Disk->fileHandle, ofs+(Previous>>1)*3, 3, &val);\r
+ break;\r
+ case FAT16:\r
+ VFS_ReadAt(Disk->fileHandle, ofs+Previous*2, 2, &ret);\r
+ val = 0;\r
+ VFS_WriteAt(Disk->fileHandle, ofs+Cluster*2, 2, &val);\r
+ break;\r
+ case FAT32:\r
+ VFS_ReadAt(Disk->fileHandle, ofs+Previous*4, 4, &ret);\r
+ val = 0;\r
+ VFS_WriteAt(Disk->fileHandle, ofs+Cluster*2, 2, &val);\r
+ break;\r
+ }\r
+ RELEASE(Disk->lFAT);\r
+ #if CACHE_FAT\r
+ }\r
+ #endif\r
+ if(Disk->type == FAT12 && ret == EOC_FAT12) ret = -1;\r
+ if(Disk->type == FAT16 && ret == EOC_FAT16) ret = -1;\r
+ if(Disk->type == FAT32 && ret == EOC_FAT32) ret = -1;\r
+ return ret;\r
+}\r
+#endif\r
+\r
+/*\r
+ * ====================\r
+ * Cluster IO\r
+ * ====================\r
+ */\r
+/**\r
+ * \brief Read a cluster\r
+ */\r
+void FAT_int_ReadCluster(tFAT_VolInfo *Disk, Uint32 Cluster, int Length, void *Buffer)\r
+{\r
+ ENTER("pDisk xCluster iLength pBuffer", Disk, Cluster, Length, Buffer);\r
+ //Log("Cluster = %i (0x%x)", Cluster, Cluster);\r
+ VFS_ReadAt(\r
+ Disk->fileHandle,\r
+ (Disk->firstDataSect + (Cluster-2)*Disk->bootsect.spc )\r
+ * Disk->bootsect.bps,\r
+ Length,\r
+ Buffer\r
+ );\r
+ LEAVE('-');\r
+}\r
+\r
+/* ====================\r
+ * File IO\r
+ * ====================\r
+ */\r
+/**\r
+ * \fn Uint64 FAT_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer)\r
+ * \brief Reads data from a specified file\r
+ */\r
+Uint64 FAT_Read(tVFS_Node *Node, Uint64 offset, Uint64 length, void *buffer)\r
+{\r
+ int preSkip, count;\r
+ int i, cluster, pos;\r
+ int bpc;\r
+ void *tmpBuf;\r
+ tFAT_VolInfo *disk = Node->ImplPtr;\r
+ \r
+ ENTER("pNode Xoffset Xlength pbuffer", Node, offset, length, buffer);\r
+ \r
+ // Calculate and Allocate Bytes Per Cluster\r
+ bpc = disk->BytesPerCluster;\r
+ tmpBuf = (void*) malloc(bpc);\r
+ if( !tmpBuf ) return 0;\r
+ \r
+ // Cluster is stored in Inode Field\r
+ cluster = Node->Inode & 0xFFFFFFFF;\r
+ \r
+ // Sanity Check offset\r
+ if(offset > Node->Size) {\r
+ LOG("Reading past EOF (%i > %i)", offset, Node->Size);\r
+ LEAVE('i', 0);\r
+ return 0;\r
+ }\r
+ // Clamp Size\r
+ if(offset + length > Node->Size) {\r
+ LOG("Reading past EOF (%lli + %lli > %lli), clamped to %lli",\r
+ offset, length, Node->Size, Node->Size - offset);\r
+ length = Node->Size - offset;\r
+ }\r
+ \r
+ // Single Cluster including offset\r
+ if(length + offset < bpc)\r
+ {\r
+ FAT_int_ReadCluster(disk, cluster, bpc, tmpBuf);\r
+ memcpy( buffer, (void*)( tmpBuf + offset%bpc ), length );\r
+ free(tmpBuf);\r
+ LEAVE('i', 1);\r
+ return length;\r
+ }\r
+ \r
+ #if 0\r
+ if( FAT_int_GetAddress(Node, offset, &addr) )\r
+ {\r
+ Log_Warning("FAT", "Offset is past end of cluster chain mark");\r
+ LEAVE('i', 0);\r
+ return 0;\r
+ }\r
+ #endif\r
+ \r
+ preSkip = offset / bpc;\r
+ \r
+ //Skip previous clusters\r
+ for(i=preSkip;i--;) {\r
+ cluster = FAT_int_GetFatValue(disk, cluster);\r
+ if(cluster == -1) {\r
+ Log_Warning("FAT", "Offset is past end of cluster chain mark");\r
+ LEAVE('i', 0);\r
+ return 0;\r
+ }\r
+ }\r
+ \r
+ // Get Count of Clusters to read\r
+ count = ((offset%bpc+length) / bpc) + 1;\r
+ \r
+ // Get buffer Position after 1st cluster\r
+ pos = bpc - offset%bpc;\r
+ \r
+ // Read 1st Cluster\r
+ FAT_int_ReadCluster(disk, cluster, bpc, tmpBuf);\r
+ memcpy(\r
+ buffer,\r
+ (void*)( tmpBuf + (bpc-pos) ),\r
+ (pos < length ? pos : length)\r
+ );\r
+ \r
+ if (count == 1) {\r
+ free(tmpBuf);\r
+ LEAVE('i', 1);\r
+ return length;\r
+ }\r
+ \r
+ cluster = FAT_int_GetFatValue(disk, cluster);\r
+ \r
+ #if DEBUG\r
+ LOG("pos = %i", pos);\r
+ LOG("Reading the rest of the clusters");\r
+ #endif\r
+ \r
+ \r
+ // Read the rest of the cluster data\r
+ for( i = 1; i < count-1; i++ )\r
+ {\r
+ FAT_int_ReadCluster(disk, cluster, bpc, tmpBuf);\r
+ memcpy((void*)(buffer+pos), tmpBuf, bpc);\r
+ pos += bpc;\r
+ cluster = FAT_int_GetFatValue(disk, cluster);\r
+ if(cluster == -1) {\r
+ Warning("FAT_Read - Read past End of Cluster Chain");\r
+ free(tmpBuf);\r
+ LEAVE('i', 0);\r
+ return 0;\r
+ }\r
+ }\r
+ \r
+ FAT_int_ReadCluster(disk, cluster, bpc, tmpBuf);\r
+ memcpy((void*)(buffer+pos), tmpBuf, length-pos);\r
+ \r
+ #if DEBUG\r
+ LOG("Free tmpBuf(0x%x) and Return", tmpBuf);\r
+ #endif\r
+ \r
+ free(tmpBuf);\r
+ LEAVE('X', length);\r
+ return length;\r
+}\r
+\r
+#if SUPPORT_WRITE\r
+/**\r
+ * \brief Write a cluster to disk\r
+ */\r
+void FAT_int_WriteCluster(tFAT_VolInfo *Disk, Uint32 Cluster, void *Buffer)\r
+{\r
+ ENTER("pDisk xCluster pBuffer", Disk, Cluster, Buffer);\r
+ VFS_ReadAt(\r
+ Disk->fileHandle,\r
+ (Disk->firstDataSect + (Cluster-2)*Disk->bootsect.spc )\r
+ * Disk->bootsect.bps,\r
+ Disk->BytesPerCluster,\r
+ Buffer\r
+ );\r
+ LEAVE('-');\r
+}\r
+\r
+/**\r
+ * \brief Write to a file\r
+ * \param Node File Node\r
+ * \param Offset Offset within file\r
+ * \param Length Size of data to write\r
+ * \param Buffer Data source\r
+ */\r
+Uint64 FAT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
+{\r
+ tFAT_VolInfo *disk = Node->ImplPtr;\r
+ void *tmpBuf;\r
+ int remLength = Length;\r
+ Uint32 cluster, tmpCluster;\r
+ int bNewCluster = 0;\r
+ \r
+ if(Offset > Node->Size) return 0;\r
+ \r
+ // Seek Clusters\r
+ cluster = Node->Inode & 0xFFFFFFFF;\r
+ while( Offset > disk->BytesPerCluster )\r
+ {\r
+ cluster = FAT_int_GetFatValue( disk, cluster );\r
+ if(cluster == -1) {\r
+ Log_Warning("FAT", "EOC Unexpectedly Reached");\r
+ return 0;\r
+ }\r
+ Offset -= disk->BytesPerCluster;\r
+ }\r
+ if( Offset == disk->BytesPerCluster )\r
+ {\r
+ Uint32 tmp = FAT_int_AllocateCluster(disk, cluster);\r
+ if(!tmp) return 0;\r
+ cluster = tmp;\r
+ Offset -= disk->BytesPerCluster;\r
+ }\r
+ \r
+ if( Offset + Length < disk->BytesPerCluster )\r
+ {\r
+ tmpBuf = malloc( disk->BytesPerCluster );\r
+ \r
+ // Read-Modify-Write\r
+ FAT_int_ReadCluster( disk, cluster, disk->BytesPerCluster, tmpBuf );\r
+ memcpy( tmpBuf + Offset, Buffer, Length );\r
+ FAT_int_WriteCluster( disk, cluster, tmpBuf );\r
+ \r
+ free(tmpBuf);\r
+ return Length;\r
+ }\r
+ \r
+ // Clean up changes within a cluster\r
+ if( Offset )\r
+ {\r
+ tmpBuf = malloc( disk->BytesPerCluster );\r
+ \r
+ // Read-Modify-Write\r
+ FAT_int_ReadCluster( disk, cluster, disk->BytesPerCluster, tmpBuf );\r
+ memcpy( tmpBuf + Offset, Buffer, disk->BytesPerCluster - Offset );\r
+ FAT_int_WriteCluster( disk, cluster, tmpBuf );\r
+ \r
+ free(tmpBuf);\r
+ \r
+ remLength -= disk->BytesPerCluster - Offset;\r
+ Buffer += disk->BytesPerCluster - Offset;\r
+ \r
+ // Get next cluster (allocating if needed)\r
+ tmpCluster = FAT_int_GetFatValue(disk, cluster);\r
+ if(tmpCluster == -1) {\r
+ tmpCluster = FAT_int_AllocateCluster(disk, cluster);\r
+ if( tmpCluster == 0 ) {\r
+ return Length - remLength;\r
+ }\r
+ }\r
+ cluster = tmpCluster;\r
+ }\r
+ \r
+ while( remLength > disk->BytesPerCluster )\r
+ {\r
+ FAT_int_WriteCluster( disk, cluster, Buffer );\r
+ Buffer += disk->BytesPerCluster;\r
+ \r
+ // Get next cluster (allocating if needed)\r
+ tmpCluster = FAT_int_GetFatValue(disk, cluster);\r
+ if(tmpCluster == -1) {\r
+ bNewCluster = 1;\r
+ tmpCluster = FAT_int_AllocateCluster(disk, cluster);\r
+ if( tmpCluster == 0 ) {\r
+ return Length - remLength;\r
+ }\r
+ }\r
+ cluster = tmpCluster;\r
+ }\r
+ \r
+ // Finish off\r
+ tmpBuf = malloc( disk->BytesPerCluster );\r
+ if( bNewCluster )\r
+ memset(tmpBuf, 0, disk->BytesPerCluster);\r
+ else\r
+ FAT_int_ReadCluster( disk, cluster, disk->BytesPerCluster, tmpBuf );\r
+ memcpy( tmpBuf, Buffer, remLength );\r
+ FAT_int_WriteCluster( disk, cluster, tmpBuf );\r
+ free( tmpBuf );\r
+ \r
+ return Length;\r
+}\r
+#endif\r
+\r
+/* ====================\r
+ * File Names & Nodes\r
+ * ====================\r
+ */\r
+/**\r
+ * \fn void FAT_int_ProperFilename(char *dest, char *src)\r
+ * \brief Converts a FAT directory entry name into a proper filename\r
+ */\r
+void FAT_int_ProperFilename(char *dest, char *src)\r
+{\r
+ int a, b;\r
+ \r
+ for( a = 0; a < 8; a++) {\r
+ if(src[a] == ' ') break;\r
+ dest[a] = src[a];\r
+ }\r
+ b = a;\r
+ a = 8;\r
+ if(src[8] != ' ')\r
+ dest[b++] = '.';\r
+ for( ; a < 11; a++, b++) {\r
+ if(src[a] == ' ') break;\r
+ dest[b] = src[a];\r
+ }\r
+ dest[b] = '\0';\r
+ #if DEBUG\r
+ //LOG("dest='%s'", dest);\r
+ #endif\r
+}\r
+\r
+/**\r
+ * \fn char *FAT_int_CreateName(fat_filetable *ft, char *LongFileName)\r
+ * \brief Converts either a LFN or a 8.3 Name into a proper name\r
+ */\r
+char *FAT_int_CreateName(fat_filetable *ft, char *LongFileName)\r
+{\r
+ char *ret;\r
+ ENTER("pft sLongFileName", ft, LongFileName);\r
+ #if USE_LFN\r
+ if(LongFileName && LongFileName[0] != '\0')\r
+ { \r
+ ret = strdup(LongFileName);\r
+ }\r
+ else\r
+ {\r
+ #endif\r
+ ret = (char*) malloc(13);\r
+ memset(ret, 13, '\0');\r
+ FAT_int_ProperFilename(ret, ft->name);\r
+ #if USE_LFN\r
+ }\r
+ #endif\r
+ LEAVE('s', ret);\r
+ return ret;\r
+}\r
+\r
+/**\r
+ * \fn tVFS_Node *FAT_int_CreateNode(tVFS_Node *parent, fat_filetable *ft)\r
+ * \brief Creates a tVFS_Node structure for a given file entry\r
+ */\r
+tVFS_Node *FAT_int_CreateNode(tVFS_Node *Parent, fat_filetable *Entry, int Pos)\r
+{\r
+ tVFS_Node node = {0};\r
+ tVFS_Node *ret;\r
+ tFAT_VolInfo *disk = Parent->ImplPtr;\r
+ \r
+ ENTER("pParent pFT", Parent, Entry);\r
+ \r
+ // Set Other Data\r
+ node.Inode = Entry->cluster | (Entry->clusterHi<<16) | (Parent->Inode << 32);\r
+ LOG("node.Inode = %llx", node.Inode);\r
+ node.ImplInt = Pos & 0xFFFF;\r
+ node.ImplPtr = disk;\r
+ node.Size = Entry->size;\r
+ LOG("Entry->size = %i", Entry->size);\r
+ node.UID = 0; node.GID = 0;\r
+ node.NumACLs = 1;\r
+ \r
+ node.Flags = 0;\r
+ if(Entry->attrib & ATTR_DIRECTORY) node.Flags |= VFS_FFLAG_DIRECTORY;\r
+ if(Entry->attrib & ATTR_READONLY) {\r
+ node.Flags |= VFS_FFLAG_READONLY;\r
+ node.ACLs = &gVFS_ACL_EveryoneRX; // R-XR-XR-X\r
+ }\r
+ else {\r
+ node.ACLs = &gVFS_ACL_EveryoneRWX; // RWXRWXRWX\r
+ }\r
+ \r
+ node.ATime = timestamp(0,0,0,\r
+ ((Entry->adate&0x1F) - 1), // Days\r
+ ((Entry->adate&0x1E0) - 1), // Months\r
+ 1980+((Entry->adate&0xFF00)>>8) // Years\r
+ );\r
+ \r
+ node.CTime = Entry->ctimems * 10; // Miliseconds\r
+ node.CTime += timestamp(\r
+ ((Entry->ctime&0x1F)<<1), // Seconds\r
+ ((Entry->ctime&0x3F0)>>5), // Minutes\r
+ ((Entry->ctime&0xF800)>>11), // Hours\r
+ ((Entry->cdate&0x1F)-1), // Days\r
+ ((Entry->cdate&0x1E0)-1), // Months\r
+ 1980+((Entry->cdate&0xFF00)>>8) // Years\r
+ );\r
+ \r
+ node.MTime = timestamp(\r
+ ((Entry->mtime&0x1F)<<1), // Seconds\r
+ ((Entry->mtime&0x3F0)>>5), // Minutes\r
+ ((Entry->mtime&0xF800)>>11), // Hours\r
+ ((Entry->mdate&0x1F)-1), // Days\r
+ ((Entry->mdate&0x1E0)-1), // Months\r
+ 1980+((Entry->mdate&0xFF00)>>8) // Years\r
+ );\r
+ \r
+ if(node.Flags & VFS_FFLAG_DIRECTORY) {\r
+ //Log_Debug("FAT", "Directory %08x has size 0x%x", node.Inode, node.Size);\r
+ node.ReadDir = FAT_ReadDir;\r
+ node.FindDir = FAT_FindDir;\r
+ #if SUPPORT_WRITE\r
+ node.MkNod = FAT_Mknod;\r
+ node.Relink = FAT_Relink;\r
+ #endif\r
+ node.Size = -1;\r
+ } else {\r
+ node.Read = FAT_Read;\r
+ #if SUPPORT_WRITE\r
+ node.Write = FAT_Write;\r
+ #endif\r
+ }\r
+ node.Close = FAT_CloseFile;\r
+ \r
+ ret = Inode_CacheNode(disk->inodeHandle, &node);\r
+ LEAVE('p', ret);\r
+ return ret;\r
+}\r
+\r
+/* ====================\r
+ * Directory IO\r
+ * ====================\r
+ */\r
+\r
+/**\r
+ * \brief Reads a sector from the disk\r
+ */\r
+int FAT_int_ReadDirSector(tVFS_Node *Node, int Sector, fat_filetable *Buffer)\r
+{\r
+ Uint64 addr;\r
+ tFAT_VolInfo *disk = Node->ImplPtr;\r
+ \r
+ ENTER("pNode iSector pEntry", Node, Sector, Buffer);\r
+ \r
+ if(FAT_int_GetAddress(Node, Sector * 512, &addr, NULL))\r
+ {\r
+ LEAVE('i', 1);\r
+ return 1;\r
+ }\r
+ \r
+ // Read Sector\r
+ if(VFS_ReadAt(disk->fileHandle, addr, 512, Buffer) != 512)\r
+ {\r
+ LEAVE('i', 1);\r
+ return 1;\r
+ }\r
+ \r
+ LEAVE('i', 0);\r
+ return 0;\r
+}\r
+\r
+#if SUPPORT_WRITE\r
+/**\r
+ * \brief Writes an entry to the disk\r
+ * \todo Support expanding a directory\r
+ * \return Zero on success, non-zero on error\r
+ */\r
+int FAT_int_WriteDirEntry(tVFS_Node *Node, int ID, fat_filetable *Entry)\r
+{\r
+ Uint64 addr = 0;\r
+ int tmp;\r
+ Uint32 cluster = 0;\r
+ tFAT_VolInfo *disk = Node->ImplPtr;\r
+ \r
+ ENTER("pNode iID pEntry", Node, ID, Entry);\r
+ \r
+ tmp = FAT_int_GetAddress(Node, ID * sizeof(fat_filetable), &addr, &cluster);\r
+ if( tmp )\r
+ {\r
+ //TODO: Allocate a cluster\r
+ cluster = FAT_int_AllocateCluster(Node->ImplPtr, cluster);\r
+ if(cluster == -1) {\r
+ Log_Warning("FAT", "Unable to allocate an other cluster for %p", Node);\r
+ LEAVE('i', 1);\r
+ return 1;\r
+ }\r
+ FAT_int_GetAddress(Node, ID * sizeof(fat_filetable), &addr, &cluster);\r
+ }\r
+ \r
+\r
+ LOG("addr = 0x%llx", addr);\r
+ \r
+ // Read Sector\r
+ VFS_WriteAt(disk->fileHandle, addr, sizeof(fat_filetable), Entry); // Read Dir Data\r
+ \r
+ LEAVE('i', 0);\r
+ return 0;\r
+}\r
+#endif\r
+\r
+#if USE_LFN\r
+// I should probably more tightly associate the LFN cache with the node\r
+// somehow, maybe by adding a field to tVFS_Node before locking it\r
+// Maybe .Cache or something like that (something that is free'd by the\r
+// Inode_UncacheNode function)\r
+ \r
+/**\r
+ * \fn char *FAT_int_GetLFN(tVFS_Node *node)\r
+ * \brief Return pointer to LFN cache entry\r
+ */\r
+char *FAT_int_GetLFN(tVFS_Node *node)\r
+{\r
+ t_lfncache *tmp;\r
+ tmp = fat_lfncache;\r
+ while(tmp)\r
+ {\r
+ if(tmp->Inode == node->Inode && tmp->Disk == node->ImplPtr)\r
+ return tmp->Name;\r
+ tmp = tmp->Next;\r
+ }\r
+ tmp = malloc(sizeof(t_lfncache));\r
+ tmp->Inode = node->Inode;\r
+ tmp->Disk = node->ImplPtr;\r
+ memset(tmp->Name, 0, 256);\r
+ \r
+ tmp->Next = fat_lfncache;\r
+ fat_lfncache = tmp;\r
+ \r
+ return tmp->Name;\r
+}\r
+\r
+/**\r
+ * \fn void FAT_int_DelLFN(tVFS_Node *node)\r
+ * \brief Delete a LFN cache entry\r
+ */\r
+void FAT_int_DelLFN(tVFS_Node *node)\r
+{\r
+ t_lfncache *tmp;\r
+ \r
+ if(!fat_lfncache) return;\r
+ \r
+ if(!fat_lfncache->Next)\r
+ {\r
+ tmp = fat_lfncache;\r
+ fat_lfncache = tmp->Next;\r
+ free(tmp);\r
+ return;\r
+ }\r
+ tmp = fat_lfncache;\r
+ while(tmp && tmp->Next)\r
+ {\r
+ if(tmp->Inode == node->Inode && tmp->Disk == node->ImplPtr)\r
+ {\r
+ free(tmp->Next);\r
+ tmp->Next = tmp->Next->Next;\r
+ return;\r
+ }\r
+ tmp = tmp->Next;\r
+ }\r
+}\r
+#endif\r
+\r
+/**\r
+ * \fn char *FAT_ReadDir(tVFS_Node *Node, int ID)\r
+ * \param Node Node structure of directory\r
+ * \param ID Directory position\r
+ */\r
+char *FAT_ReadDir(tVFS_Node *Node, int ID)\r
+{\r
+ fat_filetable fileinfo[16]; //Sizeof=32, 16 per sector\r
+ int a=0;\r
+ char *ret;\r
+ #if USE_LFN\r
+ char *lfn = NULL;\r
+ #endif\r
+ \r
+ ENTER("pNode iID", Node, ID);\r
+ \r
+ if(FAT_int_ReadDirSector(Node, ID/16, fileinfo))\r
+ {\r
+ LEAVE('n');\r
+ return NULL;\r
+ }\r
+ \r
+ // Offset in sector\r
+ a = ID % 16;\r
+\r
+ LOG("a = %i", a);\r
+ \r
+ LOG("name[0] = 0x%x", (Uint8)fileinfo[a].name[0]);\r
+ \r
+ // Check if this is the last entry\r
+ if( fileinfo[a].name[0] == '\0' ) {\r
+ Node->Size = ID;\r
+ LOG("End of list");\r
+ LEAVE('n');\r
+ return NULL; // break\r
+ }\r
+ \r
+ // Check for empty entry\r
+ if( (Uint8)fileinfo[a].name[0] == 0xE5 ) {\r
+ LOG("Empty Entry");\r
+ LEAVE('p', VFS_SKIP);\r
+ return VFS_SKIP; // Skip\r
+ }\r
+ \r
+ #if USE_LFN\r
+ // Get Long File Name Cache\r
+ lfn = FAT_int_GetLFN(Node);\r
+ if(fileinfo[a].attrib == ATTR_LFN)\r
+ {\r
+ fat_longfilename *lfnInfo;\r
+ int len;\r
+ \r
+ lfnInfo = (fat_longfilename *) &fileinfo[a];\r
+ if(lfnInfo->id & 0x40) memset(lfn, 0, 256);\r
+ // Get the current length\r
+ len = strlen(lfn);\r
+ \r
+ // Sanity Check (FAT implementations should not allow >255 bytes)\r
+ if(len + 13 > 255) return VFS_SKIP;\r
+ // Rebase all bytes\r
+ for(a=len+1;a--;) lfn[a+13] = lfn[a];\r
+ \r
+ // Append new bytes\r
+ lfn[ 0] = lfnInfo->name1[0]; lfn[ 1] = lfnInfo->name1[1];\r
+ lfn[ 2] = lfnInfo->name1[2]; lfn[ 3] = lfnInfo->name1[3];\r
+ lfn[ 4] = lfnInfo->name1[4]; \r
+ lfn[ 5] = lfnInfo->name2[0]; lfn[ 6] = lfnInfo->name2[1];\r
+ lfn[ 7] = lfnInfo->name2[2]; lfn[ 8] = lfnInfo->name2[3];\r
+ lfn[ 9] = lfnInfo->name2[4]; lfn[10] = lfnInfo->name2[5];\r
+ lfn[11] = lfnInfo->name3[0]; lfn[12] = lfnInfo->name3[1];\r
+ LOG("lfn = '%s'", lfn);\r
+ LEAVE('p', VFS_SKIP);\r
+ return VFS_SKIP;\r
+ }\r
+ #endif\r
+ \r
+ //Check if it is a volume entry\r
+ if(fileinfo[a].attrib & 0x08) {\r
+ LEAVE('p', VFS_SKIP);\r
+ return VFS_SKIP;\r
+ }\r
+ // Ignore . and ..\r
+ if(fileinfo[a].name[0] == '.') {\r
+ LEAVE('p', VFS_SKIP);\r
+ return VFS_SKIP;\r
+ } \r
+ \r
+ LOG("name='%c%c%c%c%c%c%c%c.%c%c%c'",\r
+ fileinfo[a].name[0], fileinfo[a].name[1], fileinfo[a].name[2], fileinfo[a].name[3],\r
+ fileinfo[a].name[4], fileinfo[a].name[5], fileinfo[a].name[6], fileinfo[a].name[7],\r
+ fileinfo[a].name[8], fileinfo[a].name[9], fileinfo[a].name[10] );\r
+ \r
+ #if USE_LFN\r
+ ret = FAT_int_CreateName(&fileinfo[a], lfn);\r
+ lfn[0] = '\0';\r
+ #else\r
+ ret = FAT_int_CreateName(&fileinfo[a], NULL);\r
+ #endif\r
+ \r
+ LEAVE('s', ret);\r
+ return ret;\r
+}\r
+\r
+/**\r
+ * \fn tVFS_Node *FAT_FindDir(tVFS_Node *node, char *name)\r
+ * \brief Finds an entry in the current directory\r
+ */\r
+tVFS_Node *FAT_FindDir(tVFS_Node *Node, char *Name)\r
+{\r
+ fat_filetable fileinfo[16];\r
+ char tmpName[13];\r
+ #if USE_LFN\r
+ fat_longfilename *lfnInfo;\r
+ char lfn[256];\r
+ int lfnPos=255, lfnId = -1;\r
+ #endif\r
+ int i;\r
+ tVFS_Node *tmpNode;\r
+ tFAT_VolInfo *disk = Node->ImplPtr;\r
+ Uint32 cluster;\r
+ \r
+ ENTER("pNode sname", Node, Name);\r
+ \r
+ // Fast Returns\r
+ if(!Name || Name[0] == '\0') {\r
+ LEAVE('n');\r
+ return NULL;\r
+ }\r
+ \r
+ for( i = 0; ; i++ )\r
+ {\r
+ if((i & 0xF) == 0) {\r
+ if(FAT_int_ReadDirSector(Node, i/16, fileinfo))\r
+ {\r
+ LEAVE('n');\r
+ return NULL;\r
+ }\r
+ }\r
+ \r
+ //Check if the files are free\r
+ if(fileinfo[i&0xF].name[0] == '\0') break; // End of List marker\r
+ if(fileinfo[i&0xF].name[0] == '\xE5') continue; // Free entry\r
+ \r
+ \r
+ #if USE_LFN\r
+ // Long File Name Entry\r
+ if(fileinfo[i&0xF].attrib == ATTR_LFN)\r
+ {\r
+ lfnInfo = (fat_longfilename *) &fileinfo[i&0xF];\r
+ if(lfnInfo->id & 0x40) {\r
+ memset(lfn, 0, 256);\r
+ lfnPos = 255;\r
+ }\r
+ lfn[lfnPos--] = lfnInfo->name3[1]; lfn[lfnPos--] = lfnInfo->name3[0];\r
+ lfn[lfnPos--] = lfnInfo->name2[5]; lfn[lfnPos--] = lfnInfo->name2[4];\r
+ lfn[lfnPos--] = lfnInfo->name2[3]; lfn[lfnPos--] = lfnInfo->name2[2];\r
+ lfn[lfnPos--] = lfnInfo->name2[1]; lfn[lfnPos--] = lfnInfo->name2[0];\r
+ lfn[lfnPos--] = lfnInfo->name1[4]; lfn[lfnPos--] = lfnInfo->name1[3];\r
+ lfn[lfnPos--] = lfnInfo->name1[2]; lfn[lfnPos--] = lfnInfo->name1[1];\r
+ lfn[lfnPos--] = lfnInfo->name1[0];\r
+ if((lfnInfo->id&0x3F) == 1)\r
+ {\r
+ memcpy(lfn, lfn+lfnPos+1, 256-lfnPos);\r
+ lfnId = i+1;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ // Remove LFN if it does not apply\r
+ if(lfnId != i) lfn[0] = '\0';\r
+ #endif\r
+ // Get Real Filename\r
+ FAT_int_ProperFilename(tmpName, fileinfo[i&0xF].name);\r
+ LOG("tmpName = '%s'", tmpName);\r
+ \r
+ // Only the long name is case sensitive, 8.3 is not\r
+ #if USE_LFN\r
+ if(strucmp(tmpName, Name) == 0 || strcmp(lfn, Name) == 0)\r
+ #else\r
+ if(strucmp(tmpName, Name) == 0)\r
+ #endif\r
+ {\r
+ cluster = fileinfo[i&0xF].cluster | (fileinfo[i&0xF].clusterHi << 16);\r
+ tmpNode = Inode_GetCache(disk->inodeHandle, cluster);\r
+ if(tmpNode == NULL) // Node is not cached\r
+ {\r
+ tmpNode = FAT_int_CreateNode(Node, &fileinfo[i&0xF], i);\r
+ }\r
+ LEAVE('p', tmpNode);\r
+ return tmpNode;\r
+ }\r
+ #if USE_LFN\r
+ }\r
+ #endif\r
+ }\r
+ \r
+ LEAVE('n');\r
+ return NULL;\r
+}\r
+\r
+#if SUPPORT_WRITE\r
+/**\r
+ * \fn int FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags)\r
+ * \brief Create a new node\r
+ */\r
+int FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags)\r
+{\r
+ return 0;\r
+}\r
+\r
+/**\r
+ * \fn int FAT_Relink(tVFS_Node *Node, char *OldName, char *NewName)\r
+ * \brief Rename / Delete a file\r
+ */\r
+int FAT_Relink(tVFS_Node *Node, char *OldName, char *NewName)\r
+{\r
+ tVFS_Node *child;\r
+ fat_filetable ft = {0};\r
+ int ret;\r
+ \r
+ child = FAT_FindDir(Node, OldName);\r
+ if(!child) return ENOTFOUND;\r
+ \r
+ // Delete?\r
+ if( NewName == NULL )\r
+ {\r
+ child->ImplInt |= FAT_FLAG_DELETE; // Mark for deletion on close\r
+ \r
+ // Delete from the directory\r
+ ft.name[0] = '\xE9';\r
+ FAT_int_WriteDirEntry(Node, child->ImplInt & 0xFFFF, &ft);\r
+ \r
+ // Return success\r
+ ret = EOK;\r
+ }\r
+ // Rename\r
+ else\r
+ {\r
+ Log_Warning("FAT", "Renaming no yet supported %p ('%s' => '%s')",\r
+ Node, OldName, NewName);\r
+ ret = ENOTIMPL;\r
+ }\r
+ \r
+ // Close child\r
+ child->Close( child );\r
+ return ret;\r
+}\r
+#endif\r
+\r
+/**\r
+ * \fn void FAT_CloseFile(tVFS_Node *Node)\r
+ * \brief Close an open file\r
+ */\r
+void FAT_CloseFile(tVFS_Node *Node)\r
+{\r
+ tFAT_VolInfo *disk = Node->ImplPtr;\r
+ if(Node == NULL) return ;\r
+ \r
+ #if SUPPORT_WRITE\r
+ // Update the node if it's dirty (don't bother if it's marked for\r
+ // deletion)\r
+ if( Node->ImplInt & FAT_FLAG_DIRTY && !(Node->ImplInt & FAT_FLAG_DELETE) )\r
+ {\r
+ tFAT_VolInfo buf[16];\r
+ tFAT_VolInfo *ft = &buf[ (Node->ImplInt & 0xFFFF) % 16 ];\r
+ \r
+ FAT_int_ReadDirSector(Node, (Node->ImplInt & 0xFFFF)/16, buf);\r
+ ft->size = Node->Size;\r
+ // TODO: update adate, mtime, mdate\r
+ FAT_int_WriteDirEntry(Node, Node->ImplInt & 0xFFFF, ft);\r
+ \r
+ Node->ImplInt &= ~FAT_FLAG_DIRTY;\r
+ }\r
+ #endif\r
+ \r
+ // TODO: Make this more thread safe somehow, probably by moving the\r
+ // Inode_UncacheNode higher up and saving the cluster value somewhere\r
+ if( Node->ReferenceCount == 1 )\r
+ {\r
+ // Delete LFN Cache\r
+ #if USE_LFN\r
+ if( Node->Flags & VFS_FFLAG_DIRECTORY)\r
+ FAT_int_DelLFN(Node);\r
+ #endif\r
+ \r
+ #if SUPPORT_WRITE\r
+ // Delete File\r
+ if( Node->ImplInt & FAT_FLAG_DELETE ) {\r
+ // Since the node is marked, we only need to remove it's data\r
+ Uint32 cluster = Node->Inode & 0xFFFFFFFF;\r
+ while( cluster != -1 )\r
+ cluster = FAT_int_FreeCluster(Node->ImplPtr, cluster);\r
+ }\r
+ #endif\r
+ }\r
+ \r
+ Inode_UncacheNode(disk->inodeHandle, Node->Inode);\r
+ return ;\r
+}\r
--- /dev/null
+/*\r
+ * Acess2\r
+ * FAT12/16/32 Driver\r
+ * vfs/fs/fs_fat.h\r
+ */\r
+#ifndef _FS_FAT_H_\r
+#define _FS_FAT_H_\r
+\r
+// === On Disk Structures ===\r
+/**\r
+ * \struct fat_bootsect_s\r
+ * \brief Bootsector format\r
+ */\r
+struct fat_bootsect_s\r
+{\r
+ Uint8 jmp[3]; //!< Jump Instruction\r
+ char oemname[8]; //!< OEM Name. Typically MSDOS1.1\r
+ Uint16 bps; //!< Bytes per Sector. Assumed to be 512\r
+ Uint8 spc; //!< Sectors per Cluster\r
+ Uint16 resvSectCount; //!< Number of reserved sectors at beginning of volume\r
+ Uint8 fatCount; //!< Number of copies of the FAT\r
+ Uint16 files_in_root; //!< Count of files in the root directory\r
+ Uint16 totalSect16; //!< Total sector count (FAT12/16)\r
+ Uint8 mediaDesc; //!< Media Desctiptor\r
+ Uint16 fatSz16; //!< FAT Size (FAT12/16)\r
+ Uint16 spt; //!< Sectors per track. Ignored (Acess uses LBA)\r
+ Uint16 heads; //!< Heads. Ignored (Acess uses LBA)\r
+ Uint32 hiddenCount; //!< ???\r
+ Uint32 totalSect32; //!< Total sector count (FAT32)\r
+ union {\r
+ struct {\r
+ Uint8 drvNum; //!< Drive Number. BIOS Drive ID (E.g. 0x80)\r
+ Uint8 resv; //!< Reserved byte\r
+ Uint8 bootSig; //!< Boot Signature. ???\r
+ Uint32 volId; //!< Volume ID\r
+ char label[11]; //!< Disk Label\r
+ char fsType[8]; //!< FS Type. ???\r
+ } __attribute__((packed)) fat16; //!< FAT16 Specific information\r
+ struct {\r
+ Uint32 fatSz32; //!< 32-Bit FAT Size\r
+ Uint16 extFlags; //!< Extended flags\r
+ Uint16 fsVer; //!< Filesystem Version\r
+ Uint32 rootClust; //!< Root Cluster ID\r
+ Uint16 fsInfo; //!< FS Info. ???\r
+ Uint16 backupBS; //!< Backup Bootsector Sector Offset\r
+ char resv[12]; //!< Reserved Data\r
+ Uint8 drvNum; //!< Drive Number\r
+ char resv2; //!< Reserved Data\r
+ Uint8 bootSig; //!< Boot Signature. ???\r
+ Uint32 volId; //!< Volume ID\r
+ char label[11]; //!< Disk Label\r
+ char fsType[8]; //!< Filesystem Type. ???\r
+ } __attribute__((packed)) fat32; //!< FAT32 Specific Information\r
+ }__attribute__((packed)) spec; //!< Non Shared Data\r
+ char pad[512-90]; //!< Bootsector Data (Code/Boot Signature 0xAA55)\r
+} __attribute__((packed));\r
+\r
+/**\r
+ \struct fat_filetable_s\r
+ \brief Format of a 8.3 file entry on disk\r
+*/\r
+struct fat_filetable_s {\r
+ char name[11]; //!< 8.3 Name\r
+ Uint8 attrib; //!< File Attributes.\r
+ Uint8 ntres; //!< Reserved for NT - Set to 0\r
+ Uint8 ctimems; //!< 10ths of a second ranging from 0-199 (2 seconds)\r
+ Uint16 ctime; //!< Creation Time\r
+ Uint16 cdate; //!< Creation Date\r
+ Uint16 adate; //!< Accessed Date. No Time feild though\r
+ Uint16 clusterHi; //!< High Cluster. 0 for FAT12 and FAT16\r
+ Uint16 mtime; //!< Last Modified Time\r
+ Uint16 mdate; //!< Last Modified Date\r
+ Uint16 cluster; //!< Low Word of First cluster\r
+ Uint32 size; //!< Size of file\r
+} __attribute__((packed));\r
+\r
+/**\r
+ \struct fat_longfilename_s\r
+ \brief Format of a long file name entry on disk\r
+*/\r
+struct fat_longfilename_s {\r
+ Uint8 id; //!< ID of entry. Bit 6 is set for last entry\r
+ Uint16 name1[5]; //!< 5 characters of name\r
+ Uint8 attrib; //!< Attributes. Must be ATTR_LFN\r
+ Uint8 type; //!< Type. ???\r
+ Uint8 checksum; //!< Checksum\r
+ Uint16 name2[6]; //!< 6 characters of name\r
+ Uint16 firstCluster; //!< Used for non LFN compatability. Set to 0\r
+ Uint16 name3[2]; //!< Last 2 characters of name\r
+} __attribute__((packed));\r
+\r
+/**\r
+ * \name File Attributes\r
+ * \brief Flag values for ::fat_filetable_s.attrib\r
+ * \{\r
+ */\r
+#define ATTR_READONLY 0x01 //!< Read-only file\r
+#define ATTR_HIDDEN 0x02 //!< Hidden File\r
+#define ATTR_SYSTEM 0x04 //!< System File\r
+#define ATTR_VOLUMEID 0x08 //!< Volume ID (Deprecated)\r
+#define ATTR_DIRECTORY 0x10 //!< Directory\r
+/**\r
+ * \brief File needs archiving\r
+ * \note User set flag, no significance to the FS driver\r
+ */\r
+#define ATTR_ARCHIVE 0x20\r
+/**\r
+ * \brief Meta Attribute \r
+ * \r
+ * If ::fat_filetable_s.attrib equals ATTR_LFN the file is a LFN entry\r
+ */\r
+#define ATTR_LFN (ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUMEID)\r
+/**\r
+ * \}\r
+ */\r
+\r
+/**\r
+ * \brief Internal IDs for FAT types\r
+ */\r
+enum eFatType\r
+{\r
+ FAT12, //!< FAT12 Volume\r
+ FAT16, //!< FAT16 Volume\r
+ FAT32, //!< FAT32 Volume\r
+};\r
+\r
+/**\r
+ * \name End of Cluster marks\r
+ * \brief FAT values that indicate the end of a cluster chain in\r
+ * different versions.\r
+ * \{\r
+ */\r
+#define EOC_FAT12 0x0FFF //!< FAT-12 Mark\r
+#define EOC_FAT16 0xFFFF //!< FAT-16 Mark\r
+#define EOC_FAT32 0x00FFFFFF //!< FAT-32 Mark\r
+/**\r
+ * \}\r
+ */\r
+\r
+typedef struct fat_bootsect_s fat_bootsect;\r
+typedef struct fat_filetable_s fat_filetable;\r
+typedef struct fat_longfilename_s fat_longfilename;\r
+\r
+// === Memory Structures ===\r
+/**\r
+ * \struct drv_fat_volinfo_s\r
+ * \brief Representation of a volume in memory\r
+ */\r
+struct drv_fat_volinfo_s\r
+{\r
+ int fileHandle; //!< File Handle\r
+ int type; //!< FAT Type. See eFatType\r
+ char name[12]; //!< Volume Name (With NULL Terminator)\r
+ tSpinlock lFAT; //!< Lock to prevent double-writing to the FAT\r
+ Uint32 firstDataSect; //!< First data sector\r
+ Uint32 rootOffset; //!< Root Offset (clusters)\r
+ Uint32 ClusterCount; //!< Total Cluster Count\r
+ fat_bootsect bootsect; //!< Boot Sector\r
+ tVFS_Node rootNode; //!< Root Node\r
+ int BytesPerCluster;\r
+ int inodeHandle; //!< Inode Cache Handle\r
+ #if CACHE_FAT\r
+ Uint32 *FATCache; //!< FAT Cache\r
+ #endif\r
+};\r
+\r
+typedef struct drv_fat_volinfo_s tFAT_VolInfo;\r
+\r
+#endif\r
+++ /dev/null
-#
-#
-
-OBJ = ext2.o read.o dir.o write.o
-NAME = FS_Ext2
-
--include ../Makefile.tpl
+++ /dev/null
-/*
- * Acess OS
- * Ext2 Driver Version 1
- */
-/**
- * \file dir.c
- * \brief Second Extended Filesystem Driver
- * \todo Implement file full write support
- */
-#define DEBUG 1
-#define VERBOSE 0
-#include "ext2_common.h"
-
-
-// === PROTOTYPES ===
-char *Ext2_ReadDir(tVFS_Node *Node, int Pos);
-tVFS_Node *Ext2_FindDir(tVFS_Node *Node, char *FileName);
- int Ext2_MkNod(tVFS_Node *Node, char *Name, Uint Flags);
-tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeId, char *Name);
-
-// === CODE ===
-/**
- \fn char *Ext2_ReadDir(tVFS_Node *Node, int Pos)
- \brief Reads a directory entry
-*/
-char *Ext2_ReadDir(tVFS_Node *Node, int Pos)
-{
- tExt2_Inode inode;
- char namebuf[EXT2_NAME_LEN+1];
- tExt2_DirEnt dirent;
- Uint64 Base; // Block's Base Address
- int block = 0, ofs = 0;
- int entNum = 0;
- tExt2_Disk *disk = Node->ImplPtr;
- Uint size;
-
- ENTER("pNode iPos", Node, Pos);
-
- // Read directory's inode
- Ext2_int_GetInode(Node, &inode);
- size = inode.i_size;
-
- LOG("inode.i_block[0] = 0x%x", inode.i_block[0]);
-
- // Find Entry
- // Get First Block
- // - Do this ourselves as it is a simple operation
- Base = inode.i_block[0] * disk->BlockSize;
- while(Pos -- && size > 0)
- {
- VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent);
- ofs += dirent.rec_len;
- size -= dirent.rec_len;
- entNum ++;
-
- if(ofs >= disk->BlockSize) {
- block ++;
- if( ofs > disk->BlockSize ) {
- Warning("[EXT2] Directory Entry %i of inode %i extends over a block boundary, ignoring",
- entNum-1, Node->Inode);
- }
- ofs = 0;
- Base = Ext2_int_GetBlockAddr( disk, inode.i_block, block );
- }
- }
-
- // Check for the end of the list
- if(size <= 0) {
- LEAVE('n');
- return NULL;
- }
-
- // Read Entry
- VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent );
- //LOG("dirent.inode = %i", dirent.inode);
- //LOG("dirent.rec_len = %i", dirent.rec_len);
- //LOG("dirent.name_len = %i", dirent.name_len);
- VFS_ReadAt( disk->FD, Base+ofs+sizeof(tExt2_DirEnt), dirent.name_len, namebuf );
- namebuf[ dirent.name_len ] = '\0'; // Cap off string
-
-
- // Ignore . and .. (these are done in the VFS)
- if( (namebuf[0] == '.' && namebuf[1] == '\0')
- || (namebuf[0] == '.' && namebuf[1] == '.' && namebuf[2]=='\0')) {
- LEAVE('p', VFS_SKIP);
- return VFS_SKIP; // Skip
- }
-
- LEAVE('s', namebuf);
- // Create new node
- return strdup(namebuf);
-}
-
-/**
- \fn tVFS_Node *Ext2_FindDir(tVFS_Node *node, char *filename)
- \brief Gets information about a file
- \param node vfs node - Parent Node
- \param filename String - Name of file
- \return VFS Node of file
-*/
-tVFS_Node *Ext2_FindDir(tVFS_Node *Node, char *Filename)
-{
- tExt2_Disk *disk = Node->ImplPtr;
- tExt2_Inode inode;
- char namebuf[EXT2_NAME_LEN+1];
- tExt2_DirEnt dirent;
- Uint64 Base; // Block's Base Address
- int block = 0, ofs = 0;
- int entNum = 0;
- Uint size;
-
- // Read directory's inode
- Ext2_int_GetInode(Node, &inode);
- size = inode.i_size;
-
- // Get First Block
- // - Do this ourselves as it is a simple operation
- Base = inode.i_block[0] * disk->BlockSize;
- // Find File
- while(size > 0)
- {
- VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent);
- VFS_ReadAt( disk->FD, Base+ofs+sizeof(tExt2_DirEnt), dirent.name_len, namebuf );
- namebuf[ dirent.name_len ] = '\0'; // Cap off string
- // If it matches, create a node and return it
- if(strcmp(namebuf, Filename) == 0)
- return Ext2_int_CreateNode( disk, dirent.inode, namebuf );
- // Increment pointers
- ofs += dirent.rec_len;
- size -= dirent.rec_len;
- entNum ++;
-
- // Check for end of block
- if(ofs >= disk->BlockSize) {
- block ++;
- if( ofs > disk->BlockSize ) {
- Warning("[EXT2 ] Directory Entry %i of inode %i extends over a block boundary, ignoring",
- entNum-1, Node->Inode);
- }
- ofs = 0;
- Base = Ext2_int_GetBlockAddr( disk, inode.i_block, block );
- }
- }
-
- return NULL;
-}
-
-/**
- * \fn int Ext2_MkNod(tVFS_Node *Parent, char *Name, Uint Flags)
- * \brief Create a new node
- */
-int Ext2_MkNod(tVFS_Node *Parent, char *Name, Uint Flags)
-{
- return 0;
-}
-
-// ---- INTERNAL FUNCTIONS ----
-/**
- * \fn vfs_node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID, char *Name)
- * \brief Create a new VFS Node
- */
-tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID, char *Name)
-{
- tExt2_Inode inode;
- tVFS_Node retNode;
- tVFS_Node *tmpNode;
-
- if( !Ext2_int_ReadInode(Disk, InodeID, &inode) )
- return NULL;
-
- if( (tmpNode = Inode_GetCache(Disk->CacheID, InodeID)) )
- return tmpNode;
-
-
- // Set identifiers
- retNode.Inode = InodeID;
- retNode.ImplPtr = Disk;
-
- // Set file length
- retNode.Size = inode.i_size;
-
- // Set Access Permissions
- retNode.UID = inode.i_uid;
- retNode.GID = inode.i_gid;
- retNode.NumACLs = 3;
- retNode.ACLs = VFS_UnixToAcessACL(inode.i_mode & 0777, inode.i_uid, inode.i_gid);
-
- // Set Function Pointers
- retNode.Read = Ext2_Read;
- retNode.Write = Ext2_Write;
- retNode.Close = Ext2_CloseFile;
-
- switch(inode.i_mode & EXT2_S_IFMT)
- {
- // Symbolic Link
- case EXT2_S_IFLNK:
- retNode.Flags = VFS_FFLAG_SYMLINK;
- break;
- // Regular File
- case EXT2_S_IFREG:
- retNode.Flags = 0;
- retNode.Size |= (Uint64)inode.i_dir_acl << 32;
- break;
- // Directory
- case EXT2_S_IFDIR:
- retNode.ReadDir = Ext2_ReadDir;
- retNode.FindDir = Ext2_FindDir;
- retNode.MkNod = Ext2_MkNod;
- //retNode.Relink = Ext2_Relink;
- retNode.Flags = VFS_FFLAG_DIRECTORY;
- break;
- // Unknown, Write protect and hide it to be safe
- default:
- retNode.Flags = VFS_FFLAG_READONLY;//|VFS_FFLAG_HIDDEN;
- break;
- }
-
- // Check if the file should be hidden
- //if(Name[0] == '.') retNode.Flags |= VFS_FFLAG_HIDDEN;
-
- // Set Timestamps
- retNode.ATime = now();
- retNode.MTime = inode.i_mtime * 1000;
- retNode.CTime = inode.i_ctime * 1000;
-
- // Save in node cache and return saved node
- return Inode_CacheNode(Disk->CacheID, &retNode);
-}
+++ /dev/null
-/*\r
- * Acess OS\r
- * Ext2 Driver Version 1\r
- */\r
-/**\r
- * \file fs/ext2.c\r
- * \brief Second Extended Filesystem Driver\r
- * \todo Implement file full write support\r
- */\r
-#define DEBUG 1\r
-#define VERBOSE 0\r
-#include "ext2_common.h"\r
-#include <modules.h>\r
-\r
-// === PROTOTYPES ===\r
- int Ext2_Install(char **Arguments);\r
-// Interface Functions\r
-tVFS_Node *Ext2_InitDevice(char *Device, char **Options);\r
-void Ext2_Unmount(tVFS_Node *Node);\r
-void Ext2_CloseFile(tVFS_Node *Node);\r
-// Internal Helpers\r
- int Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode);\r
-Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum);\r
-Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent);\r
-void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk);\r
-\r
-// === SEMI-GLOBALS ===\r
-MODULE_DEFINE(0, 0x5B /*v0.90*/, FS_Ext2, Ext2_Install, NULL);\r
-tExt2_Disk gExt2_disks[6];\r
- int giExt2_count = 0;\r
-tVFS_Driver gExt2_FSInfo = {\r
- "ext2", 0, Ext2_InitDevice, Ext2_Unmount, NULL\r
- };\r
-\r
-// === CODE ===\r
-\r
-/**\r
- * \fn int Ext2_Install(char **Arguments)\r
- * \brief Install the Ext2 Filesystem Driver\r
- */\r
-int Ext2_Install(char **Arguments)\r
-{\r
- VFS_AddDriver( &gExt2_FSInfo );\r
- return 1;\r
-}\r
-\r
-/**\r
- \fn tVFS_Node *Ext2_InitDevice(char *Device, char **Options)\r
- \brief Initializes a device to be read by by the driver\r
- \param Device String - Device to read from\r
- \param Options NULL Terminated array of option strings\r
- \return Root Node\r
-*/\r
-tVFS_Node *Ext2_InitDevice(char *Device, char **Options)\r
-{\r
- tExt2_Disk *disk;\r
- int fd;\r
- int groupCount;\r
- tExt2_SuperBlock sb;\r
- tExt2_Inode inode;\r
- \r
- ENTER("sDevice pOptions", Device, Options);\r
- \r
- // Open Disk\r
- fd = VFS_Open(Device, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE); //Open Device\r
- if(fd == -1) {\r
- Warning("[EXT2 ] Unable to open '%s'", Device);\r
- LEAVE('n');\r
- return NULL;\r
- }\r
- \r
- // Read Superblock at offset 1024\r
- VFS_ReadAt(fd, 1024, 1024, &sb); // Read Superblock\r
- \r
- // Sanity Check Magic value\r
- if(sb.s_magic != 0xEF53) {\r
- Warning("[EXT2 ] Volume '%s' is not an EXT2 volume", Device);\r
- VFS_Close(fd);\r
- LEAVE('n');\r
- return NULL;\r
- }\r
- \r
- // Get Group count\r
- groupCount = DivUp(sb.s_blocks_count, sb.s_blocks_per_group);\r
- LOG("groupCount = %i", groupCount);\r
- \r
- // Allocate Disk Information\r
- disk = malloc(sizeof(tExt2_Disk) + sizeof(tExt2_Group)*groupCount);\r
- if(!disk) {\r
- Warning("[EXT2 ] Unable to allocate disk structure");\r
- VFS_Close(fd);\r
- LEAVE('n');\r
- return NULL;\r
- }\r
- disk->FD = fd;\r
- memcpy(&disk->SuperBlock, &sb, 1024);\r
- disk->GroupCount = groupCount;\r
- \r
- // Get an inode cache handle\r
- disk->CacheID = Inode_GetHandle();\r
- \r
- // Get Block Size\r
- LOG("s_log_block_size = 0x%x", sb.s_log_block_size);\r
- disk->BlockSize = 1024 << sb.s_log_block_size;\r
- \r
- // Read Group Information\r
- VFS_ReadAt(\r
- disk->FD,\r
- sb.s_first_data_block * disk->BlockSize + 1024,\r
- sizeof(tExt2_Group)*groupCount,\r
- disk->Groups\r
- );\r
- \r
- #if VERBOSE\r
- LOG("Block Group 0");\r
- LOG(".bg_block_bitmap = 0x%x", disk->Groups[0].bg_block_bitmap);\r
- LOG(".bg_inode_bitmap = 0x%x", disk->Groups[0].bg_inode_bitmap);\r
- LOG(".bg_inode_table = 0x%x", disk->Groups[0].bg_inode_table);\r
- LOG("Block Group 1");\r
- LOG(".bg_block_bitmap = 0x%x", disk->Groups[1].bg_block_bitmap);\r
- LOG(".bg_inode_bitmap = 0x%x", disk->Groups[1].bg_inode_bitmap);\r
- LOG(".bg_inode_table = 0x%x", disk->Groups[1].bg_inode_table);\r
- #endif\r
- \r
- // Get root Inode\r
- Ext2_int_ReadInode(disk, 2, &inode);\r
- \r
- // Create Root Node\r
- memset(&disk->RootNode, 0, sizeof(tVFS_Node));\r
- disk->RootNode.Inode = 2; // Root inode ID\r
- disk->RootNode.ImplPtr = disk; // Save disk pointer\r
- disk->RootNode.Size = -1; // Fill in later (on readdir)\r
- disk->RootNode.Flags = VFS_FFLAG_DIRECTORY;\r
- \r
- disk->RootNode.ReadDir = Ext2_ReadDir;\r
- disk->RootNode.FindDir = Ext2_FindDir;\r
- //disk->RootNode.Relink = Ext2_Relink;\r
- \r
- // Complete root node\r
- disk->RootNode.UID = inode.i_uid;\r
- disk->RootNode.GID = inode.i_gid;\r
- disk->RootNode.NumACLs = 1;\r
- disk->RootNode.ACLs = &gVFS_ACL_EveryoneRW;\r
- \r
- #if DEBUG\r
- LOG("inode.i_size = 0x%x", inode.i_size);\r
- LOG("inode.i_block[0] = 0x%x", inode.i_block[0]);\r
- #endif\r
- \r
- LEAVE('p', &disk->RootNode);\r
- return &disk->RootNode;\r
-}\r
-\r
-/**\r
- * \fn void Ext2_Unmount(tVFS_Node *Node)\r
- * \brief Close a mounted device\r
- */\r
-void Ext2_Unmount(tVFS_Node *Node)\r
-{\r
- tExt2_Disk *disk = Node->ImplPtr;\r
- \r
- VFS_Close( disk->FD );\r
- Inode_ClearCache( disk->CacheID );\r
- memset(disk, 0, sizeof(tExt2_Disk)+disk->GroupCount*sizeof(tExt2_Group));\r
- free(disk);\r
-}\r
-\r
-/**\r
- * \fn void Ext2_CloseFile(tVFS_Node *Node)\r
- * \brief Close a file (Remove it from the cache)\r
- */\r
-void Ext2_CloseFile(tVFS_Node *Node)\r
-{\r
- tExt2_Disk *disk = Node->ImplPtr;\r
- Inode_UncacheNode(disk->CacheID, Node->Inode);\r
- return ;\r
-}\r
-\r
-//==================================\r
-//= INTERNAL FUNCTIONS =\r
-//==================================\r
-\r
-\r
-/**\r
- * \fn int Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode)\r
- * \brief Gets the inode descriptor for a node\r
- * \param Node node to get the Inode of\r
- * \param Inode Destination\r
- */\r
-int Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode)\r
-{\r
- return Ext2_int_ReadInode(Node->ImplPtr, Node->Inode, Inode);\r
-}\r
-\r
-/**\r
- * \fn int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode)\r
- * \brief Read an inode into memory\r
- */\r
-int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode)\r
-{\r
- int group, subId;\r
- \r
- //LogF("Ext2_int_ReadInode: (Disk=%p, InodeId=%i, Inode=%p)", Disk, InodeId, Inode);\r
- //ENTER("pDisk iInodeId pInode", Disk, InodeId, Inode);\r
- \r
- if(InodeId == 0) return 0;\r
- \r
- InodeId --; // Inodes are numbered starting at 1\r
- \r
- group = InodeId / Disk->SuperBlock.s_inodes_per_group;\r
- subId = InodeId % Disk->SuperBlock.s_inodes_per_group;\r
- \r
- //LOG("group=%i, subId = %i", group, subId);\r
- \r
- // Read Inode\r
- VFS_ReadAt(Disk->FD,\r
- Disk->Groups[group].bg_inode_table * Disk->BlockSize + sizeof(tExt2_Inode)*subId,\r
- sizeof(tExt2_Inode),\r
- Inode);\r
- return 1;\r
-}\r
-\r
-/**\r
- * \fn Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum)\r
- * \brief Get the address of a block from an inode's list\r
- * \param Disk Disk information structure\r
- * \param Blocks Pointer to an inode's block list\r
- * \param BlockNum Block index in list\r
- */\r
-Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum)\r
-{\r
- Uint32 *iBlocks;\r
- // Direct Blocks\r
- if(BlockNum < 12)\r
- return (Uint64)Blocks[BlockNum] * Disk->BlockSize;\r
- \r
- // Single Indirect Blocks\r
- iBlocks = malloc( Disk->BlockSize );\r
- VFS_ReadAt(Disk->FD, (Uint64)Blocks[12]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
- \r
- BlockNum -= 12;\r
- if(BlockNum < 256) {\r
- BlockNum = iBlocks[BlockNum];\r
- free(iBlocks);\r
- return (Uint64)BlockNum * Disk->BlockSize;\r
- }\r
- \r
- // Double Indirect Blocks\r
- if(BlockNum < 256*256)\r
- {\r
- VFS_ReadAt(Disk->FD, (Uint64)Blocks[13]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
- VFS_ReadAt(Disk->FD, (Uint64)iBlocks[BlockNum/256]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
- BlockNum = iBlocks[BlockNum%256];\r
- free(iBlocks);\r
- return (Uint64)BlockNum * Disk->BlockSize;\r
- }\r
- // Triple Indirect Blocks\r
- VFS_ReadAt(Disk->FD, (Uint64)Blocks[14]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
- VFS_ReadAt(Disk->FD, (Uint64)iBlocks[BlockNum/(256*256)]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
- VFS_ReadAt(Disk->FD, (Uint64)iBlocks[(BlockNum/256)%256]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
- BlockNum = iBlocks[BlockNum%256];\r
- free(iBlocks);\r
- return (Uint64)BlockNum * Disk->BlockSize;\r
-}\r
-\r
-/**\r
- * \fn Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent)\r
- * \brief Allocate an inode (from the current group preferably)\r
- * \param Disk EXT2 Disk Information Structure\r
- * \param Parent Inode ID of the parent (used to locate the child nearby)\r
- */\r
-Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent)\r
-{\r
-// Uint block = (Parent - 1) / Disk->SuperBlock.s_inodes_per_group;\r
- return 0;\r
-}\r
-\r
-/**\r
- * \fn void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk)\r
- * \brief Updates the superblock\r
- */\r
-void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk)\r
-{\r
- int bpg = Disk->SuperBlock.s_blocks_per_group;\r
- int ngrp = Disk->SuperBlock.s_blocks_count / bpg;\r
- int i;\r
- \r
- // Update Primary\r
- VFS_WriteAt(Disk->FD, 1024, 1024, &Disk->SuperBlock);\r
- \r
- // Secondaries\r
- // at Block Group 1, 3^n, 5^n, 7^n\r
- \r
- // 1\r
- if(ngrp <= 1) return;\r
- VFS_WriteAt(Disk->FD, 1*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock);\r
- \r
- // Powers of 3\r
- for( i = 3; i < ngrp; i *= 3 )\r
- VFS_WriteAt(Disk->FD, i*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock);\r
- \r
- // Powers of 5\r
- for( i = 5; i < ngrp; i *= 5 )\r
- VFS_WriteAt(Disk->FD, i*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock);\r
- \r
- // Powers of 7\r
- for( i = 7; i < ngrp; i *= 7 )\r
- VFS_WriteAt(Disk->FD, i*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock);\r
-}\r
+++ /dev/null
-/*
- * Acess OS
- * Ext2 Driver Version 1
- */
-/**
- * \file ext2_common.h
- * \brief Second Extended Filesystem Driver
- */
-#ifndef _EXT2_COMMON_H
-#define _EXT2_COMMON_H
-#include <acess.h>
-#include <vfs.h>
-#include "ext2fs.h"
-
-#define EXT2_UPDATE_WRITEBACK 1
-
-// === STRUCTURES ===
-typedef struct {
- int FD;
- int CacheID;
- tVFS_Node RootNode;
-
- tExt2_SuperBlock SuperBlock;
- int BlockSize;
-
- int GroupCount;
- tExt2_Group Groups[];
-} tExt2_Disk;
-
-// === FUNCTIONS ===
-// --- Common ---
-extern void Ext2_CloseFile(tVFS_Node *Node);
-extern int Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode);
-extern Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum);
-extern void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk);
-// --- Dir ---
-extern char *Ext2_ReadDir(tVFS_Node *Node, int Pos);
-extern tVFS_Node *Ext2_FindDir(tVFS_Node *Node, char *FileName);
-extern int Ext2_MkNod(tVFS_Node *Node, char *Name, Uint Flags);
-// --- Read ---
-extern Uint64 Ext2_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);
-extern int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode);
-// --- Write ---
-extern Uint64 Ext2_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);
-
-#endif
+++ /dev/null
-/**\r
- * Acess2\r
- * \file ext2fs.h\r
- * \brief EXT2 Filesystem Driver\r
- */\r
-#ifndef _EXT2FS_H_\r
-#define _EXT2FS_H_\r
-\r
-/**\r
- \name Inode Flag Values\r
- \{\r
-*/\r
-#define EXT2_S_IFMT 0xF000 //!< Format Mask\r
-#define EXT2_S_IFSOCK 0xC000 //!< Socket\r
-#define EXT2_S_IFLNK 0xA000 //!< Symbolic Link\r
-#define EXT2_S_IFREG 0x8000 //!< Regular File\r
-#define EXT2_S_IFBLK 0x6000 //!< Block Device\r
-#define EXT2_S_IFDIR 0x4000 //!< Directory\r
-#define EXT2_S_IFCHR 0x2000 //!< Character Device\r
-#define EXT2_S_IFIFO 0x1000 //!< FIFO\r
-#define EXT2_S_ISUID 0x0800 //!< SUID\r
-#define EXT2_S_ISGID 0x0400 //!< SGID\r
-#define EXT2_S_ISVTX 0x0200 //!< sticky bit\r
-#define EXT2_S_IRWXU 0700 //!< user access rights mask\r
-#define EXT2_S_IRUSR 0400 //!< Owner Read\r
-#define EXT2_S_IWUSR 0200 //!< Owner Write\r
-#define EXT2_S_IXUSR 0100 //!< Owner Execute\r
-#define EXT2_S_IRWXG 0070 //!< Group Access rights mask\r
-#define EXT2_S_IRGRP 0040 //!< Group Read\r
-#define EXT2_S_IWGRP 0020 //!< Group Write\r
-#define EXT2_S_IXGRP 0010 //!< Group Execute\r
-#define EXT2_S_IRWXO 0007 //!< Global Access rights mask\r
-#define EXT2_S_IROTH 0004 //!< Global Read\r
-#define EXT2_S_IWOTH 0002 //!< Global Write\r
-#define EXT2_S_IXOTH 0001 //!< Global Execute\r
-//! \}\r
-\r
-#define EXT2_NAME_LEN 255 //!< Maximum Name Length\r
-\r
-// === TYPEDEFS ===\r
-typedef struct ext2_inode_s tExt2_Inode; //!< Inode Type\r
-typedef struct ext2_super_block_s tExt2_SuperBlock; //!< Superblock Type\r
-typedef struct ext2_group_desc_s tExt2_Group; //!< Group Descriptor Type\r
-typedef struct ext2_dir_entry_s tExt2_DirEnt; //!< Directory Entry Type\r
-\r
-// === STRUCTURES ===\r
-/**\r
- * \brief EXT2 Superblock Structure\r
- */\r
-struct ext2_super_block_s {\r
- Uint32 s_inodes_count; //!< Inodes count\r
- Uint32 s_blocks_count; //!< Blocks count\r
- Uint32 s_r_blocks_count; //!< Reserved blocks count\r
- Uint32 s_free_blocks_count; //!< Free blocks count\r
- Uint32 s_free_inodes_count; //!< Free inodes count\r
- Uint32 s_first_data_block; //!< First Data Block\r
- Uint32 s_log_block_size; //!< Block size\r
- Sint32 s_log_frag_size; //!< Fragment size\r
- Uint32 s_blocks_per_group; //!< Number Blocks per group\r
- Uint32 s_frags_per_group; //!< Number Fragments per group\r
- Uint32 s_inodes_per_group; //!< Number Inodes per group\r
- Uint32 s_mtime; //!< Mount time\r
- Uint32 s_wtime; //!< Write time\r
- Uint16 s_mnt_count; //!< Mount count\r
- Sint16 s_max_mnt_count; //!< Maximal mount count\r
- Uint16 s_magic; //!< Magic signature\r
- Uint16 s_state; //!< File system state\r
- Uint16 s_errors; //!< Behaviour when detecting errors\r
- Uint16 s_pad; //!< Padding\r
- Uint32 s_lastcheck; //!< time of last check\r
- Uint32 s_checkinterval; //!< max. time between checks\r
- Uint32 s_creator_os; //!< Formatting OS\r
- Uint32 s_rev_level; //!< Revision level\r
- Uint16 s_def_resuid; //!< Default uid for reserved blocks\r
- Uint16 s_def_resgid; //!< Default gid for reserved blocks\r
- Uint32 s_reserved[235]; //!< Padding to the end of the block\r
-};\r
-\r
-/**\r
- * \struct ext2_inode_s\r
- * \brief EXT2 Inode Definition\r
- */\r
-struct ext2_inode_s {\r
- Uint16 i_mode; //!< File mode\r
- Uint16 i_uid; //!< Owner Uid\r
- Uint32 i_size; //!< Size in bytes\r
- Uint32 i_atime; //!< Access time\r
- Uint32 i_ctime; //!< Creation time\r
- Uint32 i_mtime; //!< Modification time\r
- Uint32 i_dtime; //!< Deletion Time\r
- Uint16 i_gid; //!< Group Id\r
- Uint16 i_links_count; //!< Links count\r
- Uint32 i_blocks; //!< Number of blocks allocated for the file\r
- Uint32 i_flags; //!< File flags\r
- union {\r
- Uint32 linux_reserved1; //!< Linux: Reserved\r
- Uint32 hurd_translator; //!< HURD: Translator\r
- Uint32 masix_reserved1; //!< Masix: Reserved\r
- } osd1; //!< OS dependent 1\r
- Uint32 i_block[15]; //!< Pointers to blocks\r
- Uint32 i_version; //!< File version (for NFS)\r
- Uint32 i_file_acl; //!< File ACL\r
- Uint32 i_dir_acl; //!< Directory ACL / Extended File Size\r
- Uint32 i_faddr; //!< Fragment address\r
- union {\r
- struct {\r
- Uint8 l_i_frag; //!< Fragment number\r
- Uint8 l_i_fsize; //!< Fragment size\r
- Uint16 i_pad1; //!< Padding\r
- Uint32 l_i_reserved2[2]; //!< Reserved\r
- } linux2;\r
- struct {\r
- Uint8 h_i_frag; //!< Fragment number\r
- Uint8 h_i_fsize; //!< Fragment size\r
- Uint16 h_i_mode_high; //!< Mode High Bits\r
- Uint16 h_i_uid_high; //!< UID High Bits\r
- Uint16 h_i_gid_high; //!< GID High Bits\r
- Uint32 h_i_author; //!< Creator ID\r
- } hurd2;\r
- struct {\r
- Uint8 m_i_frag; //!< Fragment number\r
- Uint8 m_i_fsize; //!< Fragment size\r
- Uint16 m_pad1; //!< Padding\r
- Uint32 m_i_reserved2[2]; //!< reserved\r
- } masix2;\r
- } osd2; //!< OS dependent 2\r
-};\r
-\r
-/**\r
- * \struct ext2_group_desc_s\r
- * \brief EXT2 Group Descriptor\r
- */\r
-struct ext2_group_desc_s {\r
- Uint32 bg_block_bitmap; //!< Blocks bitmap block\r
- Uint32 bg_inode_bitmap; //!< Inodes bitmap block\r
- Uint32 bg_inode_table; //!< Inodes table block\r
- Uint16 bg_free_blocks_count; //!< Free blocks count\r
- Uint16 bg_free_inodes_count; //!< Free inodes count\r
- Uint16 bg_used_dirs_count; //!< Directories count\r
- Uint16 bg_pad; //!< Padding\r
- Uint32 bg_reserved[3]; //!< Reserved\r
-};\r
-\r
-/**\r
- * \brief EXT2 Directory Entry\r
- * \note The name may take up less than 255 characters\r
- */\r
-struct ext2_dir_entry_s {\r
- Uint32 inode; //!< Inode number\r
- Uint16 rec_len; //!< Directory entry length\r
- Uint8 name_len; //!< Short Name Length\r
- Uint8 type; //!< File Type\r
- char name[]; //!< File name\r
-};\r
-\r
-#endif\r
+++ /dev/null
-/*
- * Acess OS
- * Ext2 Driver Version 1
- */
-/**
- * \file read.c
- * \brief Second Extended Filesystem Driver
- * \todo Implement file full write support
- */
-#define DEBUG 1
-#define VERBOSE 0
-#include "ext2_common.h"
-
-// === PROTOTYPES ===
-Uint64 Ext2_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);
- int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode);
-
-// === CODE ===
-/**
- * \fn Uint64 Ext2_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
- * \brief Read from a file
- */
-Uint64 Ext2_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
-{
- tExt2_Disk *disk = Node->ImplPtr;
- tExt2_Inode inode;
- Uint64 base;
- Uint block;
- Uint64 remLen;
-
- ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
-
- // Get Inode
- Ext2_int_GetInode(Node, &inode);
-
- // Sanity Checks
- if(Offset >= inode.i_size) {
- LEAVE('i', 0);
- return 0;
- }
- if(Offset + Length > inode.i_size)
- Length = inode.i_size - Offset;
-
- block = Offset / disk->BlockSize;
- Offset = Offset / disk->BlockSize;
- base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
- if(base == 0) {
- Warning("[EXT2 ] NULL Block Detected in INode 0x%llx", Node->Inode);
- LEAVE('i', 0);
- return 0;
- }
-
- // Read only block
- if(Length <= disk->BlockSize - Offset)
- {
- VFS_ReadAt( disk->FD, base+Offset, Length, Buffer);
- LEAVE('X', Length);
- return Length;
- }
-
- // Read first block
- remLen = Length;
- VFS_ReadAt( disk->FD, base + Offset, disk->BlockSize - Offset, Buffer);
- remLen -= disk->BlockSize - Offset;
- Buffer += disk->BlockSize - Offset;
- block ++;
-
- // Read middle blocks
- while(remLen > disk->BlockSize)
- {
- base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
- if(base == 0) {
- Warning("[EXT2 ] NULL Block Detected in INode 0x%llx", Node->Inode);
- LEAVE('i', 0);
- return 0;
- }
- VFS_ReadAt( disk->FD, base, disk->BlockSize, Buffer);
- Buffer += disk->BlockSize;
- remLen -= disk->BlockSize;
- block ++;
- }
-
- // Read last block
- base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
- VFS_ReadAt( disk->FD, base, remLen, Buffer);
-
- LEAVE('X', Length);
- return Length;
-}
+++ /dev/null
-/*
- * Acess OS
- * Ext2 Driver Version 1
- */
-/**
- * \file write.c
- * \brief Second Extended Filesystem Driver
- * \todo Implement file full write support
- */
-#define DEBUG 1
-#define VERBOSE 0
-#include "ext2_common.h"
-
-// === PROTOYPES ===
-Uint64 Ext2_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);
-Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock);
-
-// === CODE ===
-/**
- * \fn Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
- * \brief Write to a file
- */
-Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
-{
- tExt2_Disk *disk = Node->ImplPtr;
- tExt2_Inode inode;
- Uint64 base;
- Uint64 retLen;
- Uint block;
- Uint64 allocSize;
- int bNewBlocks = 0;
-
- Debug_HexDump("Ext2_Write", Buffer, Length);
-
- Ext2_int_GetInode(Node, &inode);
-
- // Get the ammount of space already allocated
- // - Round size up to block size
- // - block size is a power of two, so this will work
- allocSize = (inode.i_size + disk->BlockSize) & ~(disk->BlockSize-1);
-
- // Are we writing to inside the allocated space?
- if( Offset < allocSize )
- {
- // Will we go out of it?
- if(Offset + Length > allocSize) {
- bNewBlocks = 1;
- retLen = allocSize - Offset;
- } else
- retLen = Length;
-
- // Within the allocated space
- block = Offset / disk->BlockSize;
- Offset %= disk->BlockSize;
- base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
-
- // Write only block (if only one)
- if(Offset + retLen <= disk->BlockSize) {
- VFS_WriteAt(disk->FD, base+Offset, retLen, Buffer);
- if(!bNewBlocks) return Length;
- goto addBlocks; // Ugh! A goto, but it seems unavoidable
- }
-
- // Write First Block
- VFS_WriteAt(disk->FD, base+Offset, disk->BlockSize-Offset, Buffer);
- Buffer += disk->BlockSize-Offset;
- retLen -= disk->BlockSize-Offset;
- block ++;
-
- // Write middle blocks
- while(retLen > disk->BlockSize)
- {
- base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
- VFS_WriteAt(disk->FD, base, disk->BlockSize, Buffer);
- Buffer += disk->BlockSize;
- retLen -= disk->BlockSize;
- block ++;
- }
-
- // Write last block
- base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
- VFS_WriteAt(disk->FD, base, retLen, Buffer);
- if(!bNewBlocks) return Length; // Writing in only allocated space
- }
-
-addBlocks:
- ///\todo Implement block allocation
- Warning("[EXT2] File extending is not yet supported");
-
- return 0;
-}
-
-/**
- * \fn Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock)
- * \brief Allocate a block from the best possible location
- * \param Disk EXT2 Disk Information Structure
- * \param PrevBlock Previous block ID in the file
- */
-Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock)
-{
- int bpg = Disk->SuperBlock.s_blocks_per_group;
- Uint blockgroup = PrevBlock / bpg;
- Uint bitmap[Disk->BlockSize/sizeof(Uint)];
- Uint bitsperblock = 8*Disk->BlockSize;
- int i, j = 0;
- Uint block;
-
- // Are there any free blocks?
- if(Disk->SuperBlock.s_free_blocks_count == 0) return 0;
-
- if(Disk->Groups[blockgroup].bg_free_blocks_count > 0)
- {
- // Search block group's bitmap
- for(i = 0; i < bpg; i++)
- {
- // Get the block in the bitmap block
- j = i & (bitsperblock-1);
-
- // Read in if needed
- if(j == 0) {
- VFS_ReadAt(
- Disk->FD,
- (Uint64)Disk->Groups[blockgroup].bg_block_bitmap + i / bitsperblock,
- Disk->BlockSize,
- bitmap
- );
- }
-
- // Fast Check
- if( bitmap[j/32] == -1 ) {
- j = (j + 31) & ~31;
- continue;
- }
-
- // Is the bit set?
- if( bitmap[j/32] & (1 << (j%32)) )
- continue;
-
- // Ooh! We found one
- break;
- }
- if( i < bpg ) {
- Warning("[EXT2 ] Inconsistency detected, Group Free Block count is non-zero when no free blocks exist");
- goto checkAll; // Search the entire filesystem for a free block
- // Goto needed for neatness
- }
-
- // Mark as used
- bitmap[j/32] |= (1 << (j%32));
- VFS_WriteAt(
- Disk->FD,
- (Uint64)Disk->Groups[blockgroup].bg_block_bitmap + i / bitsperblock,
- Disk->BlockSize,
- bitmap
- );
- block = i;
- Disk->Groups[blockgroup].bg_free_blocks_count --;
- #if EXT2_UPDATE_WRITEBACK
- //Ext2_int_UpdateBlockGroup(blockgroup);
- #endif
- }
- else
- {
- checkAll:
- Warning("[EXT2 ] TODO - Implement using blocks outside the current block group");
- return 0;
- }
-
- // Reduce global count
- Disk->SuperBlock.s_free_blocks_count --;
- #if EXT2_UPDATE_WRITEBACK
- Ext2_int_UpdateSuperblock(Disk);
- #endif
-
- return block;
-}
+++ /dev/null
-#
-#
-
-OBJ = main.o
-NAME = FS_NFS
-
--include ../Makefile.tpl
+++ /dev/null
-/*
- * Acess2 - NFS Driver
- * By John Hodge (thePowersGang)
- * This file is published under the terms of the Acess licence. See the
- * file COPYING for details.
- *
- * common.h - Common definitions
- */
-#ifndef _COMMON_H_
-#define _COMMON_H_
-
-typedef struct sNFS_Connection
-{
- int FD;
- tIPAddr Host;
- char *Base;
- tVFS_Node Node;
-} tNFS_Connection;
-
-#endif
+++ /dev/null
-/*
- * Acess2 - NFS Driver
- * By John Hodge (thePowersGang)
- * This file is published under the terms of the Acess licence. See the
- * file COPYING for details.
- *
- * main.c - Driver core
- */
-#define DEBUG 1
-#define VERBOSE 0
-#include "common.h"
-#include <modules.h>
-
-// === PROTOTYPES ===
- int NFS_Install(char **Arguments);
-tVFS_Node *NFS_InitDevice(char *Devices, char **Options);
-void NFS_Unmount(tVFS_Node *Node);
-
-// === GLOBALS ===
-MODULE_DEFINE(0, 0x32 /*v0.5*/, FS_NFS, NFS_Install, NULL);
-tVFS_Driver gNFS_FSInfo = {"nfs", 0, NFS_InitDevice, NFS_Unmount, NULL};
-
-tNFS_Connection *gpNFS_Connections;
-
-// === CODE ===
-/**
- * \brief Installs the NFS driver
- */
-int NFS_Install(char **Arguments)
-{
- VFS_AddDriver( &gNFS_FSInfo );
- return 1;
-}
-
-/**
- * \brief Mount a NFS share
- */
-tVFS_Node *NFS_InitDevice(char *Device, char **Options)
-{
- char *path, *host;
- tNFS_Connection *conn;
-
- path = strchr( Device, ':' ) + 1;
- host = strndup( Device, (int)(path-Device)-1 );
-
- conn = malloc( sizeof(tNFS_Connection) );
-
- if( !IPTools_GetAddress(host, &conn->IP) ) {
- free(conn);
- return NULL;
- }
- free(host);
-
- conn->FD = IPTools_OpenUdpClient( &conn->Host );
- if(conn->FD == -1) {
- free(conn);
- return NULL;
- }
-
- conn->Base = strdup( path );
- conn->RootNode.ImplPtr = conn;
- conn->RootNode.Flags = VFS_FFLAG_DIRECTORY;
-
- conn->RootNode.ReadDir = NFS_ReadDir;
- conn->RootNode.FindDir = NFS_FindDir;
- conn->RootNode.Close = NULL;
-
- return &conn->RootNode;
-}
-
-void NFS_Unmount(tVFS_Node *Node)
-{
-
-}
--- /dev/null
+<?php
+$lGenDate = date("Y-m-d H:i");
+$gOutput = <<<EOF
+/*
+ * Acess2 InitRD
+ * InitRD Data
+ * Generated $lGenDate
+ */
+#include "initrd.h"
+
+EOF;
+
+$lines = file($argv[1]);
+
+$lDepth = 0;
+$lTree = array();
+$lStack = array( array("",array()) );
+foreach($lines as $line)
+{
+ $line = trim($line);
+ if(preg_match('/^Dir\s+"([^"]+)"\s+{$/', $line, $matches))
+ {
+ $new = array($matches[1], array());
+ array_push($lStack, $new);
+ $lDepth ++;
+ continue;
+ }
+ if($line == "}")
+ {
+ $lDepth --;
+ $lStack[$lDepth][1][] = array_pop($lStack);
+ continue;
+ }
+ if(preg_match('/^File\s+"([^"]+)"\s+"([^"]+)"$/', $line, $matches))
+ {
+ $lStack[$lDepth][1][] = array($matches[1], $matches[2]);
+ continue;
+ }
+ echo "ERROR: $line\n";
+ exit(0);
+}
+
+function hd($fp)
+{
+ return "0x".str_pad( dechex(ord(fgetc($fp))), 2, "0", STR_PAD_LEFT );
+}
+
+function ProcessFolder($prefix, $items)
+{
+ global $gOutput;
+ foreach($items as $i=>$item)
+ {
+ if(is_array($item[1]))
+ {
+ ProcessFolder("{$prefix}_{$i}", $item[1]);
+
+ $gOutput .= "tInitRD_File {$prefix}_{$i}_entries[] = {\n";
+ foreach($item[1] as $j=>$child)
+ {
+ if($j) $gOutput .= ",\n";
+ $gOutput .= "\t{\"".addslashes($child[0])."\",&{$prefix}_{$i}_{$j}}";
+ }
+ $gOutput .= "\n};\n";
+
+ $size = count($item[1]);
+ $gOutput .= <<<EOF
+tVFS_Node {$prefix}_{$i} = {
+ .NumACLs = 1,
+ .ACLs = &gVFS_ACL_EveryoneRX,
+ .Flags = VFS_FFLAG_DIRECTORY,
+ .Size = $size,
+ .ImplPtr = {$prefix}_{$i}_entries,
+ .ReadDir = InitRD_ReadDir,
+ .FindDir = InitRD_FindDir
+};
+
+EOF;
+ }
+ else {
+ if(!file_exists($item[1])) {
+ echo "ERROR: '{$item[1]}' does not exist\n",
+ exit(1);
+ }
+ $size = filesize($item[1]);
+
+ $gOutput .= "Uint8 {$prefix}_{$i}_data[] = {\n";
+ $fp = fopen($item[1], "rb");
+ for( $j = 0; $j + 16 < $size; $j += 16 )
+ {
+ $gOutput .= "\t";
+ $gOutput .= hd($fp).",".hd($fp).",";
+ $gOutput .= hd($fp).",".hd($fp).",";
+ $gOutput .= hd($fp).",".hd($fp).",";
+ $gOutput .= hd($fp).",".hd($fp).",";
+ $gOutput .= hd($fp).",".hd($fp).",";
+ $gOutput .= hd($fp).",".hd($fp).",";
+ $gOutput .= hd($fp).",".hd($fp).",";
+ $gOutput .= hd($fp).",".hd($fp).",\n";
+ }
+ $gOutput .= "\t";
+ for( ; $j < $size; $j ++ )
+ {
+ if( $j & 15 ) $gOutput .= ",";
+ $gOutput .= hd($fp);
+ }
+ fclose($fp);
+ $gOutput .= "\n};\n";
+ $gOutput .= <<<EOF
+tVFS_Node {$prefix}_{$i} = {
+ .NumACLs = 1,
+ .ACLs = &gVFS_ACL_EveryoneRX,
+ .Flags = 0,
+ .Size = $size,
+ .ImplPtr = {$prefix}_{$i}_data,
+ .Read = InitRD_ReadFile
+};
+
+EOF;
+ }
+ }
+}
+
+//print_r($lStack);
+//exit(1);
+
+ProcessFolder("gInitRD_Files", $lStack[0][1]);
+
+$gOutput .= "tInitRD_File gInitRD_Root_Files[] = {\n";
+foreach($lStack[0][1] as $j=>$child)
+{
+ if($j) $gOutput .= ",\n";
+ $gOutput .= "\t{\"".addslashes($child[0])."\",&gInitRD_Files_{$j}}";
+}
+$gOutput .= "\n};\n";
+$nRootFiles = count($lStack[0][1]);
+$gOutput .= <<<EOF
+tVFS_Node gInitRD_RootNode = {
+ .NumACLs = 1,
+ .ACLs = &gVFS_ACL_EveryoneRX,
+ .Flags = VFS_FFLAG_DIRECTORY,
+ .Size = $nRootFiles,
+ .ImplPtr = gInitRD_Root_Files,
+ .ReadDir = InitRD_ReadDir,
+ .FindDir = InitRD_FindDir
+};
+EOF;
+
+$fp = fopen($argv[2], "w");
+fputs($fp, $gOutput);
+fclose($fp);
+?>
--- /dev/null
+# InitRD Filesystem Driver
+#
+
+OBJ = main.o files.o
+NAME = InitRD
+
+-include ../Makefile.tpl
+
+files.c: GenerateInitRD.php files.lst
+ php GenerateInitRD.php files.lst files.c
--- /dev/null
+Dir "SBin" {
+ File "init" "../../../Usermode/Applications/init"
+ File "login" "../../../Usermode/Applications/login"
+}
+Dir "Bin" {
+ File "CLIShell" "../../../Usermode/Applications/CLIShell"
+ File "ls" "../../../Usermode/Applications/ls"
+ File "cat" "../../../Usermode/Applications/cat"
+ File "mount" "../../../Usermode/Applications/mount"
+}
+Dir "Libs" {
+ File "ld-acess.so" "../../../Usermode/Libraries/ld-acess.so"
+ File "libacess.so" "../../../Usermode/Libraries/libacess.so"
+ File "libc.so.1" "../../../Usermode/Libraries/libc.so.1"
+ File "libgcc.so" "../../../Usermode/Libraries/libgcc.so"
+}
+Dir "Conf" {
+ File "BootConf.cfg" "../../../Usermode/Filesystem/Conf/BootConf.cfg"
+}
--- /dev/null
+/*
+ */
+#ifndef _INITRD_H_
+#define _INITRD_H_
+
+#include <acess.h>
+#include <vfs.h>
+
+typedef struct sInitRD_File
+{
+ char *Name;
+ tVFS_Node *Node;
+} tInitRD_File;
+
+
+// === Functions ===
+extern Uint64 InitRD_ReadFile(tVFS_Node *Node, Uint64 Offset, Uint64 Size, void *Buffer);
+extern char *InitRD_ReadDir(tVFS_Node *Node, int ID);
+extern tVFS_Node *InitRD_FindDir(tVFS_Node *Node, char *Name);
+
+#endif
--- /dev/null
+/*
+ * Acess OS
+ * InitRD Driver Version 1
+ */
+#include "initrd.h"
+#include <modules.h>
+
+// === IMPORTS ==
+extern tVFS_Node gInitRD_RootNode;
+
+// === PROTOTYPES ===
+ int InitRD_Install(char **Arguments);
+tVFS_Node *InitRD_InitDevice(char *Device, char **Arguments);
+void InitRD_Unmount(tVFS_Node *Node);
+Uint64 InitRD_ReadFile(tVFS_Node *Node, Uint64 Offset, Uint64 Size, void *Buffer);
+char *InitRD_ReadDir(tVFS_Node *Node, int ID);
+tVFS_Node *InitRD_FindDir(tVFS_Node *Node, char *Name);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, 0x0A, FS_InitRD, InitRD_Install, NULL);
+tVFS_Driver gInitRD_FSInfo = {
+ "initrd", 0, InitRD_InitDevice, InitRD_Unmount, NULL
+ };
+
+/**
+ * \brief Register initrd with the kernel
+ */
+int InitRD_Install(char **Arguments)
+{
+ VFS_AddDriver( &gInitRD_FSInfo );
+ return MODULE_ERR_OK;
+}
+
+/**
+ * \brief Mount the InitRD
+ */
+tVFS_Node *InitRD_InitDevice(char *Device, char **Arguments)
+{
+ return &gInitRD_RootNode;
+}
+
+/**
+ * \brief Unmount the InitRD
+ */
+void InitRD_Unmount(tVFS_Node *Node)
+{
+}
+
+/**
+ * \brief Read from a file
+ */
+Uint64 InitRD_ReadFile(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+ if(Offset > Node->Size)
+ return 0;
+ if(Offset + Length > Node->Size)
+ Length = Node->Size - Offset;
+
+ memcpy(Buffer, Node->ImplPtr+Offset, Length);
+
+ return Length;
+}
+
+/**
+ * \brief Read from a directory
+ */
+char *InitRD_ReadDir(tVFS_Node *Node, int ID)
+{
+ tInitRD_File *dir = Node->ImplPtr;
+
+ if(ID >= Node->Size)
+ return NULL;
+
+ return strdup(dir[ID].Name);
+}
+
+/**
+ * \brief Find an element in a directory
+ */
+tVFS_Node *InitRD_FindDir(tVFS_Node *Node, char *Name)
+{
+ int i;
+ tInitRD_File *dir = Node->ImplPtr;
+
+ //Log("InirRD_FindDir: Name = '%s'", Name);
+
+ for( i = 0; i < Node->Size; i++ )
+ {
+ if(strcmp(Name, dir[i].Name) == 0)
+ return dir[i].Node;
+ }
+
+ return NULL;
+}
+CATEGORY = FS
-include ../../Makefile.tpl
--- /dev/null
+#
+#
+
+OBJ = main.o
+NAME = NFS
+
+-include ../Makefile.tpl
--- /dev/null
+/*
+ * Acess2 - NFS Driver
+ * By John Hodge (thePowersGang)
+ * This file is published under the terms of the Acess licence. See the
+ * file COPYING for details.
+ *
+ * common.h - Common definitions
+ */
+#ifndef _COMMON_H_
+#define _COMMON_H_
+
+typedef struct sNFS_Connection
+{
+ int FD;
+ tIPAddr Host;
+ char *Base;
+ tVFS_Node Node;
+} tNFS_Connection;
+
+#endif
--- /dev/null
+/*
+ * Acess2 - NFS Driver
+ * By John Hodge (thePowersGang)
+ * This file is published under the terms of the Acess licence. See the
+ * file COPYING for details.
+ *
+ * main.c - Driver core
+ */
+#define DEBUG 1
+#define VERBOSE 0
+#include "common.h"
+#include <modules.h>
+
+// === PROTOTYPES ===
+ int NFS_Install(char **Arguments);
+tVFS_Node *NFS_InitDevice(char *Devices, char **Options);
+void NFS_Unmount(tVFS_Node *Node);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, 0x32 /*v0.5*/, FS_NFS, NFS_Install, NULL);
+tVFS_Driver gNFS_FSInfo = {"nfs", 0, NFS_InitDevice, NFS_Unmount, NULL};
+
+tNFS_Connection *gpNFS_Connections;
+
+// === CODE ===
+/**
+ * \brief Installs the NFS driver
+ */
+int NFS_Install(char **Arguments)
+{
+ VFS_AddDriver( &gNFS_FSInfo );
+ return 1;
+}
+
+/**
+ * \brief Mount a NFS share
+ */
+tVFS_Node *NFS_InitDevice(char *Device, char **Options)
+{
+ char *path, *host;
+ tNFS_Connection *conn;
+
+ path = strchr( Device, ':' ) + 1;
+ host = strndup( Device, (int)(path-Device)-1 );
+
+ conn = malloc( sizeof(tNFS_Connection) );
+
+ if( !IPTools_GetAddress(host, &conn->IP) ) {
+ free(conn);
+ return NULL;
+ }
+ free(host);
+
+ conn->FD = IPTools_OpenUdpClient( &conn->Host );
+ if(conn->FD == -1) {
+ free(conn);
+ return NULL;
+ }
+
+ conn->Base = strdup( path );
+ conn->RootNode.ImplPtr = conn;
+ conn->RootNode.Flags = VFS_FFLAG_DIRECTORY;
+
+ conn->RootNode.ReadDir = NFS_ReadDir;
+ conn->RootNode.FindDir = NFS_FindDir;
+ conn->RootNode.Close = NULL;
+
+ return &conn->RootNode;
+}
+
+void NFS_Unmount(tVFS_Node *Node)
+{
+
+}
lastID = giARP_LastUpdateID;
// Create request
- Log("[ARP4 ] Asking for address %i.%i.%i.%i",
+ Log_Log("ARP4", "Asking for address %i.%i.%i.%i",
Address.B[0], Address.B[1], Address.B[2], Address.B[3]
);
req.HWType = htons(0x0001); // Ethernet
gaARP_Cache4[i].IP = SWAddr;
}
- Log("[ARP ] Caching %i.%i.%i.%i (%02x:%02x:%02x:%02x:%02x:%02x) in %i",
+ Log_Log("ARP4", "Caching %i.%i.%i.%i (%02x:%02x:%02x:%02x:%02x:%02x) in %i",
SWAddr.B[0], SWAddr.B[1], SWAddr.B[2], SWAddr.B[3],
HWAddr.B[0], HWAddr.B[1], HWAddr.B[2], HWAddr.B[3], HWAddr.B[4], HWAddr.B[5],
i
// Sanity Check Packet
if( Length < sizeof(tArpRequest4) ) {
- Log("[ARP ] Recieved undersized packet");
+ Log_Log("ARP", "Recieved undersized packet");
return ;
}
if( ntohs(req4->Type) != 0x0800 ) {
- Log("[ARP ] Recieved a packet with a bad type 0x%x", ntohs(req4->Type));
+ Log_Log("ARP", "Recieved a packet with a bad type 0x%x", ntohs(req4->Type));
return ;
}
if( req4->HWSize != 6 ) {
- Log("[ARP ] Recieved a packet with HWSize != 6 (%i)", req4->HWSize);
+ Log_Log("ARP", "Recieved a packet with HWSize != 6 (%i)", req4->HWSize);
return;
}
if( !MAC_EQU(req4->SourceMac, From) ) {
- Log("[ARP ] ARP spoofing detected", req4->HWSize);
+ Log_Log("ARP", "ARP spoofing detected "
+ "(%02x%02x:%02x%02x:%02x%02x != %02x%02x:%02x%02x:%02x%02x)",
+ req4->SourceMac.B[0], req4->SourceMac.B[1], req4->SourceMac.B[2],
+ req4->SourceMac.B[3], req4->SourceMac.B[4], req4->SourceMac.B[5],
+ From.B[0], From.B[1], From.B[2],
+ From.B[3], From.B[4], From.B[5]
+ );
return;
}
{
if(gICMP_PingSlots[i].Interface == NULL) break;
}
- if(gICMP_PingSlots[i].Interface == NULL) break;
+ if( i < PING_SLOTS ) break;
Threads_Yield();
}
gICMP_PingSlots[i].Interface = Interface;
int NRef;
tMacAddr MacAddr;
+ int DeviceLen;
char Device[];
};
#define IP4_SET(t,v) (t).L = (v).L;
#define IP6_SET(t,v) memcpy(&(t),&(v),sizeof(tIPv6))
-#define MAC_EQU(a,b) memcmp(&(a),&(b),sizeof(tMacAddr))
+#define MAC_EQU(a,b) (memcmp(&(a),&(b),sizeof(tMacAddr))==0)
#define IP4_EQU(a,b) ((a).L==(b).L)
-#define IP6_EQU(a,b) memcmp(&(a),&(b),sizeof(tIPv6))
+#define IP6_EQU(a,b) (memcmp(&(a),&(b),sizeof(tIPv6))==0)
// === FUNCTIONS ===
#define htonb(v) (v)
hdr->Destination = Address;
hdr->HeaderChecksum = IPv4_Checksum(hdr, sizeof(tIPv4Header));
- Log("[IPv4 ] Sending packet to %i.%i.%i.%i",
+ Log_Log("IPv4", "Sending packet to %i.%i.%i.%i",
Address.B[0], Address.B[1], Address.B[2], Address.B[3]);
Link_SendPacket(Iface->Adapter, IPV4_ETHERNET_ID, to, bufSize, buf);
return 1;
int dataLength;
if(Length < sizeof(tIPv4Header)) return;
- //Log("[IPv4 ] Version = %i", hdr->Version);
- Log("[IPv4 ] HeaderLength = %i", hdr->HeaderLength);
- Log("[IPv4 ] DiffServices = %i", hdr->DiffServices);
- Log("[IPv4 ] TotalLength = %i", ntohs(hdr->TotalLength) );
- //Log("[IPv4 ] Identifcation = %i", ntohs(hdr->Identifcation) );
- //Log("[IPv4 ] TTL = %i", hdr->TTL );
- Log("[IPv4 ] Protocol = %i", hdr->Protocol );
- //Log("[IPv4 ] HeaderChecksum = 0x%x", ntohs(hdr->HeaderChecksum) );
- Log("[IPv4 ] Source = %i.%i.%i.%i",
+ //Log_Log("IPv4", "Version = %i", hdr->Version);
+ Log_Log("IPv4", "HeaderLength = %i", hdr->HeaderLength);
+ Log_Log("IPv4", "DiffServices = %i", hdr->DiffServices);
+ Log_Log("IPv4", "TotalLength = %i", ntohs(hdr->TotalLength) );
+ //Log_Log("IPv4", "Identifcation = %i", ntohs(hdr->Identifcation) );
+ //Log_Log("IPv4", "TTL = %i", hdr->TTL );
+ Log_Log("IPv4", "Protocol = %i", hdr->Protocol );
+ //Log_Log("IPv4", "HeaderChecksum = 0x%x", ntohs(hdr->HeaderChecksum) );
+ Log_Log("IPv4", "Source = %i.%i.%i.%i",
hdr->Source.B[0], hdr->Source.B[1], hdr->Source.B[2], hdr->Source.B[3] );
- Log("[IPv4 ] Destination = %i.%i.%i.%i",
+ Log_Log("IPv4", "Destination = %i.%i.%i.%i",
hdr->Destination.B[0], hdr->Destination.B[1],
hdr->Destination.B[2], hdr->Destination.B[3] );
// Check that the version IS IPv4
if(hdr->Version != 4) {
- Log("[IPv4 ] hdr->Version(%i) != 4", hdr->Version);
+ Log_Log("IPv4", "hdr->Version(%i) != 4", hdr->Version);
return;
}
// Check Packet length
if( ntohs(hdr->TotalLength) > Length) {
- Log("[IPv4 ] hdr->TotalLength(%i) > Length(%i)", ntohs(hdr->TotalLength), Length);
+ Log_Log("IPv4", "hdr->TotalLength(%i) > Length(%i)", ntohs(hdr->TotalLength), Length);
return;
}
// Get Interface (allowing broadcasts)
iface = IPv4_GetInterface(Adapter, hdr->Destination, 1);
if(!iface) {
- Log("[IPv4 ] Ignoring Packet (Not for us)");
+ Log_Log("IPv4", "Ignoring Packet (Not for us)");
return; // Not for us? Well, let's ignore it
}
if( gaIPv4_Callbacks[hdr->Protocol] )
gaIPv4_Callbacks[hdr->Protocol] (iface, &hdr->Source, dataLength, data);
else
- Log("[IPv4 ] Unknown Protocol %i", hdr->Protocol);
+ Log_Log("IPv4", "Unknown Protocol %i", hdr->Protocol);
}
/**
for( i = giRegisteredTypes; i -- ; )
{
if(gaRegisteredTypes[i].Type == Type) {
- Warning("[NET ] Attempt to register 0x%x twice", Type);
+ Log_Warning("NET", "Attempt to register 0x%x twice", Type);
return ;
}
// Ooh! Free slot!
{
tmp = realloc(gaRegisteredTypes, (giRegisteredTypes+1)*sizeof(*gaRegisteredTypes));
if(!tmp) {
- Warning("[NET ] Out of heap space!");
+ Log_Warning("NET", "Out of heap space!");
return ;
}
i = giRegisteredTypes;
Uint8 buf[bufSize]; // dynamic stack arrays ftw!
tEthernetHeader *hdr = (void*)buf;
- Log("[NET ] Sending %i bytes to %02x:%02x:%02x:%02x:%02x:%02x (Type 0x%x)",
+ Log_Log("NET", "Sending %i bytes to %02x:%02x:%02x:%02x:%02x:%02x (Type 0x%x)",
Length, To.B[0], To.B[1], To.B[2], To.B[3], To.B[4], To.B[5], Type);
hdr->Dest = To;
int tid = Proc_SpawnWorker(); // Create a new worker thread
if(tid < 0) {
- Warning("[NET ] Unable to create watcher thread for '%s'", Adapter->Device);
+ Log_Warning("NET", "Unable to create watcher thread for '%s'", Adapter->Device);
return ;
}
if(tid > 0) {
- Log("[NET ] Watching '%s' using tid %i", Adapter->Device, tid);
+ Log_Log("NET", "Watching '%s' using tid %i", Adapter->Device, tid);
return ;
}
if(ret == -1) break;
if(ret <= sizeof(tEthernetHeader)) {
- Log("[NET ] Recieved an undersized packet");
+ Log_Log("NET", "Recieved an undersized packet");
continue;
}
- Log("[NET ] Packet from %02x:%02x:%02x:%02x:%02x:%02x",
+ Log_Log("NET", "Packet from %02x:%02x:%02x:%02x:%02x:%02x",
hdr->Src.B[0], hdr->Src.B[1], hdr->Src.B[2],
hdr->Src.B[3], hdr->Src.B[4], hdr->Src.B[5]
);
- Log("[NET ] to %02x:%02x:%02x:%02x:%02x:%02x",
+ Log_Log("NET", "to %02x:%02x:%02x:%02x:%02x:%02x",
hdr->Dest.B[0], hdr->Dest.B[1], hdr->Dest.B[2],
hdr->Dest.B[3], hdr->Dest.B[4], hdr->Dest.B[5]
);
checksum = *(Uint32*)&hdr->Data[ret-sizeof(tEthernetHeader)-4];
- Log("[NET ] Checksum 0x%08x", checksum);
+ Log_Log("NET", "Checksum 0x%08x", checksum);
// Check if there is a registered callback for this packet type
for( i = giRegisteredTypes; i--; )
}
// No? Ignore it
if( i == -1 ) {
- Log("[NET ] Unregistered type 0x%x", ntohs(hdr->Type));
+ Log_Log("NET", "Unregistered type 0x%x", ntohs(hdr->Type));
continue;
}
);
}
- Log("[NET ] Watcher terminated (file closed)");
+ Log_Log("NET", "Watcher terminated (file closed)");
}
// From http://www.cl.cam.ac.uk/research/srg/bluebook/21/crc/node6.html
DevFS_AddDevice( &gIP_DriverInfo );
- return 1;
+ return MODULE_ERR_OK;
}
/**
*/
int IPStack_AddFile(tSocketFile *File)
{
- Log("IPStack_AddFile: %s", File->Name);
+ Log_Log("IPStack", "Added file '%s'", File->Name);
File->Next = gIP_FileTemplates;
gIP_FileTemplates = File;
return 0;
{
tSocketFile *file = gIP_FileTemplates;
while(Pos-- && file) {
- Log("IPStack_Iface_ReadDir: %s", file->Name);
file = file->Next;
}
for(;file;file = file->Next)
{
if( strcmp(file->Name, Name) == 0 ) break;
- Log("IPStack_Iface_FindDir: strcmp('%s', '%s')", file->Name, Name);
}
if(!file) return NULL;
"get_address", "set_address",
"getset_subnet",
"get_gateway", "set_gateway",
+ "get_device",
"ping",
NULL
};
}
break;
+ /*
+ * get_device
+ * - Gets the name of the attached device
+ */
+ case 10:
+ if( Data == NULL )
+ LEAVE_RET('i', iface->Adapter->DeviceLen);
+ if( !CheckMem( Data, iface->Adapter->DeviceLen+1 ) )
+ LEAVE_RET('i', -1);
+ strcpy( Data, iface->Adapter->Device );
+ return iface->Adapter->DeviceLen;
+
/*
* ping
* - Send an ICMP Echo
*/
- case 10:
+ case 11:
switch(iface->Type)
{
case 0:
int IPStack_AddInterface(char *Device)
{
tInterface *iface;
+ tAdapter *card;
ENTER("sDevice", Device);
+ card = IPStack_GetAdapter(Device);
+
iface = malloc(sizeof(tInterface));
if(!iface) {
LEAVE('i', -2);
// Create Node
iface->Node.ImplPtr = iface;
- iface->Node.ImplInt = giIP_NextIfaceId++;
iface->Node.Flags = VFS_FFLAG_DIRECTORY;
iface->Node.Size = -1;
iface->Node.NumACLs = 1;
return -1; // Return ERR_YOUFAIL
}
+ // Delay setting ImplInt until after the adapter is opened
+ // Keeps things simple
+ iface->Node.ImplInt = giIP_NextIfaceId++;
+
// Append to list
LOCK( &glIP_Interfaces );
if( gIP_Interfaces ) {
// Fill Structure
strcpy( dev->Device, Path );
dev->NRef = 1;
+ dev->DeviceLen = strlen(Path);
// Open Device
dev->DeviceFD = VFS_Open( dev->Device, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE );
hdr.SequenceNumber = Conn->NextSequenceSend;
hdr.DataOffset = (sizeof(tTCPHeader)/4) << 4;
hdr.Flags = TCP_FLAG_SYN;
- hdr.WindowSize = 0; // TODO
+ hdr.WindowSize = 0xFFFF; // Max
hdr.Checksum = 0; // TODO
hdr.UrgentPointer = 0;
tTCPListener *srv;
tTCPConnection *conn;
- Log("[TCP ] SourcePort = %i, DestPort = %i",
+ Log_Log("TCP", "SourcePort = %i, DestPort = %i",
ntohs(hdr->SourcePort), ntohs(hdr->DestPort));
- Log("[TCP ] SequenceNumber = 0x%x", ntohl(hdr->SequenceNumber));
- Log("[TCP ] AcknowlegementNumber = 0x%x", ntohl(hdr->AcknowlegementNumber));
- Log("[TCP ] DataOffset = %i", hdr->DataOffset >> 4);
- Log("[TCP ] Flags = {");
- Log("[TCP ] CWR = %B, ECE = %B",
+ Log_Log("TCP", "SequenceNumber = 0x%x", ntohl(hdr->SequenceNumber));
+ Log_Log("TCP", "AcknowlegementNumber = 0x%x", ntohl(hdr->AcknowlegementNumber));
+ Log_Log("TCP", "DataOffset = %i", hdr->DataOffset >> 4);
+ Log_Log("TCP", "Flags = {");
+ Log_Log("TCP", " CWR = %B, ECE = %B",
!!(hdr->Flags & TCP_FLAG_CWR), !!(hdr->Flags & TCP_FLAG_ECE));
- Log("[TCP ] URG = %B, ACK = %B",
+ Log_Log("TCP", " URG = %B, ACK = %B",
!!(hdr->Flags & TCP_FLAG_URG), !!(hdr->Flags & TCP_FLAG_ACK));
- Log("[TCP ] PSH = %B, RST = %B",
+ Log_Log("TCP", " PSH = %B, RST = %B",
!!(hdr->Flags & TCP_FLAG_PSH), !!(hdr->Flags & TCP_FLAG_RST));
- Log("[TCP ] SYN = %B, FIN = %B",
+ Log_Log("TCP", " SYN = %B, FIN = %B",
!!(hdr->Flags & TCP_FLAG_SYN), !!(hdr->Flags & TCP_FLAG_FIN));
- Log("[TCP ] }");
- Log("[TCP ] WindowSize = %i", htons(hdr->WindowSize));
- Log("[TCP ] Checksum = 0x%x", htons(hdr->Checksum));
- Log("[TCP ] UrgentPointer = 0x%x", htons(hdr->UrgentPointer));
+ Log_Log("TCP", "}");
+ Log_Log("TCP", "WindowSize = %i", htons(hdr->WindowSize));
+ Log_Log("TCP", "Checksum = 0x%x", htons(hdr->Checksum));
+ Log_Log("TCP", "UrgentPointer = 0x%x", htons(hdr->UrgentPointer));
if( Length > (hdr->DataOffset >> 4)*4 )
{
// Check the destination port
if(srv->Port != htons(hdr->DestPort)) continue;
- Log("[TCP ] Matches server %p", srv);
+ Log_Log("TCP", "Matches server %p", srv);
// Is this in an established connection?
for( conn = srv->Connections; conn; conn = conn->Next )
{
- Log("[TCP ] conn->Interface(%p) == Interface(%p)",
+ Log_Log("TCP", "conn->Interface(%p) == Interface(%p)",
conn->Interface, Interface);
// Check that it is coming in on the same interface
if(conn->Interface != Interface) continue;
// Check Source Port
- Log("[TCP ] conn->RemotePort(%i) == hdr->SourcePort(%i)",
+ Log_Log("TCP", "conn->RemotePort(%i) == hdr->SourcePort(%i)",
conn->RemotePort, ntohs(hdr->SourcePort));
if(conn->RemotePort != ntohs(hdr->SourcePort)) continue;
if(conn->Interface->Type == 4 && !IP4_EQU(conn->RemoteIP.v4, *(tIPv4*)Address))
continue;
- Log("[TCP ] Matches connection %p", conn);
+ Log_Log("TCP", "Matches connection %p", conn);
// We have a response!
TCP_INT_HandleConnectionPacket(conn, hdr, Length);
return;
}
- Log("[TCP ] Opening Connection");
+ Log_Log("TCP", "Opening Connection");
// Open a new connection (well, check that it's a SYN)
if(hdr->Flags != TCP_FLAG_SYN) {
- Log("[TCP ] Packet is not a SYN");
+ Log_Log("TCP", "Packet is not a SYN");
return ;
}
}
}
- Log("[TCP ] No Match");
+ Log_Log("TCP", "No Match");
}
/**
// Get length of data
dataLen = Length - (Header->DataOffset>>4)*4;
- Log("[TCP ] HandleConnectionPacket - dataLen = %i", dataLen);
+ Log_Log("TCP", "HandleConnectionPacket - dataLen = %i", dataLen);
if(Header->Flags & TCP_FLAG_ACK) {
// TODO: Process an ACKed Packet
- Log("[TCP ] Conn %p, Packet 0x%x ACKed", Connection, Header->AcknowlegementNumber);
+ Log_Log("TCP", "Conn %p, Packet 0x%x ACKed", Connection, Header->AcknowlegementNumber);
}
if(dataLen == 0) return ;
// Is this packet the next expected packet?
if( pkt->Sequence != Connection->NextSequenceRcv )
{
- tTCPStoredPacket *tmp, *prev;
+ tTCPStoredPacket *tmp, *prev = NULL;
- Log("[TCP ] Out of sequence packet (0x%08x != 0x%08x)",
+ Log_Log("TCP", "Out of sequence packet (0x%08x != 0x%08x)",
pkt->Sequence, Connection->NextSequenceRcv);
// No? Well, let's cache it and look at it later
{
// Ooh, Goodie! Add it to the recieved list
TCP_INT_AppendRecieved(Connection, pkt);
- Connection->NextSequenceRcv ++;
+ if(dataLen)
+ Connection->NextSequenceRcv += dataLen;
+ else
+ Connection->NextSequenceRcv += 1;
// TODO: This should be moved out of the watcher thread,
// so that a single lost packet on one connection doesn't cause
// all connections on the interface to lag.
TCP_INT_UpdateRecievedFromFuture(Connection);
- }
- // TODO: Check ACK code validity
- Header->AcknowlegementNumber = ntohl(pkt->Sequence);
- Header->SequenceNumber = ntohl(Connection->NextSequenceSend);
- Header->Flags &= TCP_FLAG_SYN;
- Header->Flags = TCP_FLAG_ACK;
- TCP_SendPacket( Connection, sizeof(tTCPHeader), Header );
+ // TODO: Check ACK code validity
+ Header->AcknowlegementNumber = ntohl(pkt->Sequence) + dataLen;
+ Header->SequenceNumber = ntohl(Connection->NextSequenceSend);
+ Header->Flags &= TCP_FLAG_SYN;
+ Header->Flags = TCP_FLAG_ACK;
+ TCP_SendPacket( Connection, sizeof(tTCPHeader), Header );
+ }
}
/**
// --- Server
tVFS_Node *TCP_Server_Init(tInterface *Interface)
{
- tTCPListener *srv = malloc( sizeof(tTCPListener) );
+ tTCPListener *srv;
+
+ srv = malloc( sizeof(tTCPListener) );
+
+ Log_Debug("TCP", "srv = %p", srv);
+
+ if( srv == NULL ) {
+ Log_Warning("TCP", "malloc failed for listener (%i) bytes", sizeof(tTCPListener));
+ return NULL;
+ }
srv->Interface = Interface;
srv->Port = 0;
tTCPConnection *conn;
char *ret;
- Log("[TCP ] Thread %i waiting for a connection", Threads_GetTID());
+ Log_Log("TCP", "Thread %i waiting for a connection", Threads_GetTID());
for(;;)
{
LOCK( &srv->lConnections );
else // Else, mark this as used
TCP_AllocatePort(srv->Port);
- Log("[TCP ] Server %p listening on port %i", srv, srv->Port);
+ Log_Log("TCP", "Server %p listening on port %i", srv, srv->Port);
return srv->Port;
}
--- /dev/null
+#
+# EDI - Extensible Driver Interface
+#
+# Acess Interface
+
+
+OBJ = main.o edi.o
+NAME = EDI
+
+-include ../Makefile.tpl
--- /dev/null
+/*! \file acess-edi.h
+ * \brief Acess Specific EDI Objects
+ *
+ * Contains documentation and information for
+ * - Timers
+ */
+
+/* Copyright (c) 2006 John Hodge
+ * Permission is granted to copy, distribute and/or modify this document
+ * under the terms of the GNU Free Documentation License, Version 1.2
+ * or any later version published by the Free Software Foundation;
+ * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+ * Texts. A copy of the license is included in the file entitled "COPYING". */
+
+#ifndef ACESS_EDI_H
+#define ACESS_EDI_H
+
+#include "edi_objects.h"
+
+/// \brief Name of Acess EDI Time Class
+#define ACESS_TIMER_CLASS "ACESSEDI-TIMER"
+
+#ifndef IMPLEMENTING_EDI
+/*! \brief int32_t ACESSEDI-TIMER.init_timer(uint32_t Delay, void (*Callback)(int), int Arg);
+ *
+ * Takes a timer pointer and intialises the timer object to fire after \a Delay ms
+ * When the timer fires, \a Callback is called with \a Arg passed to it.
+ */
+EDI_DEFVAR int32_t (*init_timer)(object_pointer port_object, uint32_t Delay, void (*fcn)(int), int arg);
+
+/*! \brief void ACESSEDI-TIMER.disable_timer();
+ *
+ * Disables the timer and prevents it from firing
+ * After this has been called, the timer can then be initialised again.
+ */
+EDI_DEFVAR void (*disable_timer)(object_pointer port_object);
+
+
+#endif // defined(IMPLEMENTING_EDI)
+
+#endif
--- /dev/null
+#ifndef EDI_H
+
+/* Copyright (c) 2006 Eli Gottlieb.
+ * Permission is granted to copy, distribute and/or modify this document
+ * under the terms of the GNU Free Documentation License, Version 1.2
+ * or any later version published by the Free Software Foundation;
+ * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+ * Texts. A copy of the license is included in the file entitled "COPYING". */
+
+#define EDI_H
+/*! \file edi.h
+ * \brief The unitive EDI header to include others, start EDI, and stop EDI.
+ *
+ * Data structures and algorithms this header represents:
+ * DATA STRUCTURE: CLASS QUOTAS - The runtime and the driver have the right to set a quota on how many objects of a given class
+ * owned by that party the other may construct. These quotas are kept internally by the driver or runtime, are optional and are
+ * exposed to the other party via the quota() function (for quotas of runtime-owned classes) and the k_quota() function pointer given
+ * to the runtime by the driver.
+ *
+ * ALGORITHMS: INITIALIZATION AND SHUTDOWN - On initialization of the runtime's EDI environment for this driver it calls the
+ * driver's driver_init() routine (which must match driver_init_t) to initialize the driver with a list of EDI objects the runtime
+ * thinks the driver should run with. The driver then initializes. This can include calling edi_negotiate_resources() to try and
+ * obtain more or different objects. Eventually driver_init() returns an edi_initialization_t structure containing its quota
+ * function and the list of classes belonging to the driver which the runtime can construct. Either the driver or the runtime can
+ * shut down EDI by calling edi_shutdown(), which in turn calls the driver's driver_finish() routine. On shutdown all objects, of
+ * classes belonging to both the runtime and driver, are destroyed. */
+
+#include "edi_objects.h"
+#include "edi_dma_streams.h"
+#include "edi_pthreads.h"
+#include "edi_port_io.h"
+#include "edi_memory_mapping.h"
+#include "edi_devices.h"
+#include "edi_interrupts.h"
+
+/*! \brief A pointer to a function the runtime can call if it fails to construct one of the driver's classes to find out what the
+ * runtime's quota is for that class.
+ *
+ * A pointer to a function which takes an edi_string_t as a parameter and returns in int32_t. This function follows the same
+ * semantics as the quota() function, returning the number of objects of the given class that can be constructed, -1 for infinity or
+ * -2 for an erroneous class name. It is used to tell the runtime the location of such a function in the driver so that the runtime
+ * can check quotas on driver-owned classes. */
+typedef int32_t (*k_quota_t)(edi_string_t resource_class);
+/*!\struct edi_initialization_t
+ * \brief Structure containing driver classes available to the runtime and the driver's quota function after the driver has initialized.
+ *
+ * Structure containing driver classes available to runtime, the driver's quota function and the driver's name provided to the runtime
+ * after the driver has initialized. driver_bus, vendor_id, and device_id are all optional fields which coders should consider
+ * supplementary information. Kernels can require these fields if they so please, but doing so for devices which don't run on a Vendor
+ * ID/Product ID supporting bus is rather unwise. */
+typedef struct {
+ /*!\brief The number of driver classes in the driver_classes array. */
+ int32_t num_driver_classes;
+ /*!\brief An array of declarations of driver classes available to the runtime.
+ *
+ * This array should not necessarily contain the entire list of EDI classes implemented by the driver. Instead, it should
+ * contain a list of those classes which the driver has correctly initialized itself to provide instances of with full
+ * functionality. */
+ edi_class_declaration_t *driver_classes;
+ /*!\brief The driver's quota function. */
+ k_quota_t k_quota;
+ /*!\brief The driver's name. */
+ edi_string_t driver_name;
+ /*!\brief The bus of the device this driver wants to drive, if applicable.
+ *
+ * The driver does not have to supply this field, and can also supply "MULTIPLE BUSES" here to indicate that it drives devices
+ * on multiple buses. */
+ edi_string_t driver_bus;
+ /*!\brief The driver's vendor ID, if applicable.
+ *
+ * The driver does not need to supply this field, and should supply -1 to indicate that it does not wish to. */
+ int16_t vendor_id;
+ /*!\brief The driver's device ID, if applicable.
+ *
+ * The driver does not need to supply this field, but can supply it along with vendor_id. If either vendor_id or this field are
+ * set to -1 the runtime should consider this field not supplied. */
+ int16_t driver_id;
+} edi_initialization_t;
+/*!\brief A pointer to a driver's initialization function.
+ *
+ * The protocol for the driver's initialization function. The runtime gives the driver a set of EDI objects representing the
+ * resources it thinks the driver should run with. This function returns an edi_initialization_t structure containing declarations
+ * of the EDI classes the driver can make available to the runtime after initialization. If any member of that structure contains 0
+ * or NULL, it is considered invalid and the runtime should destroy the driver without calling its driver_finish() routine. */
+typedef edi_initialization_t (*driver_init_t)(int32_t num_resources,edi_object_metadata_t *resources);
+/*!\brief Requests more resources from the runtime. Can be called during driver initialization.
+ *
+ * Called to negotiate with the runtime for the right to create further EDI objects/obtain further resources owned by the runtime.
+ * When the driver calls this routine, the runtime decides whether to grant more resources. If yes, this call returns true, and the
+ * driver can proceed to try and create the objects it desires, in addition to destroying EDI objects it doesn't want. Otherwise,
+ * it returns false.
+ * The driver must deal with whatever value this routine returns. */
+bool edi_negotiate_resources();
+
+/*! \brief Returns the driver's quota of objects for a given runtime-owned class.
+ *
+ * This function takes an edi_string_t with the name of a runtime-owned class in it and returns the number of objects of that class
+ * which drivers can construct, -1 for infinity, or -2 for an erroneous class name. */
+int32_t quota(edi_string_t resource_class);
+/*! \brief Sends a string to the operating systems debug output or logging facilities. */
+void edi_debug_write(uint32_t debug_string_length, char *debug_string);
+/*! \brief This call destroys all objects and shuts down the entire EDI environment of the driver.
+ *
+ * This function shuts down EDI as described in INITIALIZATION AND SHUTDOWN above. All objects are destroyed, EDI functions can no
+ * longer be successfully called, etc. This function only succeeds when EDI has already been initialized, so it returns -1 when EDI
+ * hasn't been, 1 on success, or 0 for all other errors. */
+int32_t shutdown_edi(void);
+
+/*!\brief A pointer to the driver's finishing/shutdown function.
+ *
+ * The protocol for the driver's shutting down. This function should do anything the driver wants done before it dies. */
+typedef void (*driver_finish_t)();
+
+#endif
--- /dev/null
+#ifndef EDI_DEVICES_H
+
+/* Copyright (c) 2006 Eli Gottlieb.
+ * Permission is granted to copy, distribute and/or modify this document
+ * under the terms of the GNU Free Documentation License, Version 1.2
+ * or any later version published by the Free Software Foundation;
+ * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+ * Texts. A copy of the license is included in the file entitled "COPYING". */
+
+/* Edited by thePowersGang (John Hodge) June 2009
+ * - Add #ifdef EDI_MAIN_FILE
+ */
+
+#define EDI_DEVICES_H
+
+/*! \file edi_devices.h
+ * \brief Declaration and description of simple classes for implementation by EDI drivers to represent hardware devices.
+ *
+ * Data structures and algorithms this header represents:
+ *
+ * DATA STRUCTURE AND ALGORITHM: BASIC DEVICES - There are two functions, select() for waiting on devices and ioctl() for
+ * controlling them, common to many POSIX devices. Implementations of EDI-CHARACTER-DEVICE or EDI-BLOCK-DEVICE may implement either of
+ * these or both, and users of such objects much query for the methods to see if they're supported. Obviously, runtime or driver
+ * developers don't *need* to support these.
+ *
+ * DATA STRUCTURE AND ALGORITHM: CHARACTER DEVICES - The class EDI-CHARACTER-DEVICE provides a very basic interface to character
+ * devices, which read and write streams of characters. As such, this class only provides read() and write(). The calls attempt a
+ * likeness to POSIX.
+ *
+ * DATA STRUCTURE AND ALGORITHM: BLOCK DEVICES - The class EDI-BLOCK-DEVICE provides a very basic interface to block devices, which
+ * can read(), write() and seek() to blocks of a specific size in an array of blocks with a specific size. Its declarations and
+ * semantics should behave like those of most POSIX operating systems.
+ *
+ * Note that EDI runtimes should not implement these classes. Their declarations are provided for drivers to implement. */
+
+#include "edi_objects.h"
+
+/* Methods common to all EDI device classes specified in this header. */
+
+/*!\brief EAGAIN returned by functions for block and character devices.
+ *
+ * Means that the amount of data the device has ready is less than count. */
+#define EAGAIN -1
+/*!\brief EBADOBJ returned by functions for block and character devices.
+ *
+ * Means that the object passed as the method's this point was not a valid object of the needed class. */
+#define EBADOBJ -2
+/*!\brief EINVAL returned by functions for block and character devices.
+ *
+ * Means that the method got passed invalid parameters. */
+#ifdef EINVAL
+# undef EINVAL
+#endif
+#define EINVAL -3
+
+/*!\brief select() type to wait until device is writable. */
+#define EDI_SELECT_WRITABLE 0
+/*!\brief select() type to wait until device is readable. */
+#define EDI_SELECT_READABLE 1
+
+/*!\brief Argument to seek(). Sets the block offset (ie: the "current block" index) to the given whence value. */
+#define EDI_SEEK_SET 0
+/*!\brief Argument to seek(). Sets the block offset (ie: the "current block" index) to its current value + whence. */
+#define EDI_SEEK_CURRENT 1
+
+#ifdef EDI_MAIN_FILE
+/*!\brief Arguments to EDI's basic select() function. */
+edi_variable_declaration_t select_arguments[2] = {{"pointer void","device",1},
+ {"unsigned int32_t","select_type",1}};
+/*!\brief Declaration of EDI's basic select() function.
+ *
+ * Contrary to the POSIX version, this select() puts its error codes in its return value. */
+edi_function_declaration_t select_declaration = {"int32_t","edi_device_select",0,2,select_arguments,NULL};
+#else
+extern edi_function_declaration_t select_declaration; // Declare for non main files
+#endif
+
+#ifdef EDI_MAIN_FILE
+/*!\brief Arguments to EDI's basic ioctl() function. */
+edi_variable_declaration_t ioctl_arguments[3] = {{"pointer void","device",1},{"int32_t","request",1},{"pointer void","argp",1}};
+/*!\brief Declaration of EDI's basic ioctl() function.
+ *
+ * Contrary to the POSIX version, this ioctl() puts its error codes in its return value. */
+edi_function_declaration_t ioctl_declaration = {"int32_t","edi_device_ioctl",0,3,ioctl_arguments,NULL};
+#else
+extern edi_class_declaration_t ioctl_declaration; // Declare for non main files
+#endif
+
+#ifdef EDI_MAIN_FILE
+/*!\brief Declaration of the arguments EDI-CHARACTER-DEVICE's read() and write() methods. */
+edi_variable_declaration_t chardev_read_write_arguments[3] = {{"pointer void","chardev",1},
+ {"pointer void","buffer",1},
+ {"unsigned int32_t","char_count",1}};
+/*!\brief Declarations of the methods of EDI-CHARACTER-DEVICE, read() and write().
+ *
+ * The code pointers of these function declarations are all given as NULL. Driver developers implementing EDI-CHARACTER-DEVICE should
+ * fill in these entries with pointers to their own functions. */
+EDI_DEFVAR edi_function_declaration_t chardev_methods[2]= {{"int32_t","edi_chardev_read",0,3,chardev_read_write_arguments,NULL},
+ {"int32_t","edi_chardev_write",0,3,chardev_read_write_arguments,NULL}};
+/*!\brief Declaration of the EDI-CHARACTER-DEVICE class.
+ *
+ * Driver developers implementing this class should fill in their own values for constructor, destructor, and possibly even parent
+ * before passing the filled-in structure to the EDI runtime. */
+EDI_DEFVAR edi_class_declaration_t chardev_class = {"EDI-CHARACTER-DEVICE",0,2,chardev_methods,NULL,NULL,NULL};
+#else
+extern edi_class_declaration_t chardev_class; // Declare for non main files
+#endif
+
+#ifdef EDI_MAIN_FILE
+/*!\brief Arguments to EDI-BLOCK-DEVICE's read() and write() methods. */
+edi_variable_declaration_t blockdev_read_write_arguments[3] = {{"pointer void","blockdev",1},
+ {"pointer void","buffer",1},
+ {"unsigned int32_t","blocks",1}};
+/*!\brief Arguments to EDI-BLOCK-DEVICE's seek() method. */
+edi_variable_declaration_t blockdev_seek_arguments[3] = {{"pointer void","blockdev",1},
+ {"int32_t","offset",1},
+ {"int32_t","whence",1}};
+/*!\brief Declaration of the methods of EDI-BLOCK-DEVICE, read(), write(), seek(), and get_block_size().
+ *
+ * The code pointers of these function declarations are all given as NULL. Driver developers implementing EDI-BLOCK-DEVICE should fill
+ * these entries in with pointers to their own functions. */
+edi_function_declaration_t blockdev_methods[4] = {{"int32_t","edi_blockdev_read",0,3,blockdev_read_write_arguments,NULL},
+ {"int32_t","edi_blockdev_write",0,3,blockdev_read_write_arguments,NULL},
+ {"int32_t","edi_blockdev_seek",0,3,blockdev_seek_arguments,NULL},
+ {"unsigned int32_t","edi_blockdev_get_block_size",0,0,NULL,NULL}};
+/*!\brief Declaration of the EDI-BLOCK-DEVICE class.
+ *
+ * Driver developers implementing this class should fill in their own values for constructor, destructor, and possibly even parent
+ * before passing the filled-in structure to the EDI runtime. */
+edi_class_declaration_t blockdev_class = {"EDI-BLOCK-DEVICE",0,4,blockdev_methods,NULL,NULL,NULL};
+#else
+extern edi_class_declaration_t blockdev_class; // Declare for non main files
+#endif
+
+#endif
--- /dev/null
+#ifndef EDI_DMA_STREAMS_H
+
+/* Copyright (c) 2006 Eli Gottlieb.
+ * Permission is granted to copy, distribute and/or modify this document
+ * under the terms of the GNU Free Documentation License, Version 1.2
+ * or any later version published by the Free Software Foundation;
+ * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+ * Texts. A copy of the license is included in the file entitled "COPYING". */
+
+#define EDI_DMA_STREAMS_H
+
+/*! \file edi_dma_streams.h
+ * \brief EDI's stream subclass for handling Direct Memory Access hardware.
+ *
+ * Data structures and algorithms this header represents:
+ *
+ * DATA STRUCTURE: DMA STREAMS - DMA streams are objects of the class EDI-STREAM-DMA used to pass data between a buffer of
+ * memory and the computer's DMA hardware. It is the responsibility of the object to allocate memory for its stream memory buffer
+ * which can be used with DMA hardware and to program the DMA hardware for transmissions. DMA streams can be bidirectional if the
+ * correct DMA mode is used. */
+
+#include "edi_objects.h"
+
+#define DMA_STREAM_CLASS "EDI-STREAM-DMA"
+
+/*! \brief The name of the EDI DMA stream class.
+ *
+ * An edi_string_t with the class name "EDI-STREAM-DMA" in it. */
+#if defined(EDI_MAIN_FILE) || defined(IMPLEMENTING_EDI)
+const edi_string_t dma_stream_class = DMA_STREAM_CLASS;
+#else
+extern const edi_string_t dma_stream_class;
+#endif
+
+#ifndef IMPLEMENTING_EDI
+/*! \brief int32_t EDI-STREAM-DMA.init_dma_stream(unsigned int32_t channel,unsigned int32_t mode,unsigned int32_t buffer_pages);
+ *
+ * Pointer to the init_dma_stream() method of class EDI-STREAM-DMA, which initializes a DMA stream with a DMA channel, DMA mode, and
+ * the number of DMA-accessible memory pages to keep as a buffer. It will only work once per stream object. It's possible return
+ * values are 1 for sucess, -1 for invalid DMA channel, -2 for invalid DMA mode, -3 for inability to allocate enough buffer pages and
+ * 0 for all other errors. */
+EDI_DEFVAR int32_t (*init_dma_stream)(object_pointer stream, uint32_t channel, uint32_t mode, uint32_t buffer_pages);
+/*! \brief int32_t EDI-STREAM-DMA.transmit(data_pointer *anchor,unsigned int32 num_bytes,bool sending);
+ *
+ * Pointer to the dma_stream_transmit() method of class EDI-STREAM-DMA, which transmits the given number of bytes of data through
+ * the DMA stream to/from the given anchor (either source or destination), in the given direction. It returns 1 on success, -1 on
+ * an uninitialized or invalid DMA stream object, -2 when the anchor was NULL or otherwise invalid, -3 if the DMA stream can't
+ * transmit in the given direction, and 0 for all other errors. */
+EDI_DEFVAR int32_t (*dma_stream_transmit)(object_pointer stream, data_pointer anchor, uint32_t num_bytes, bool sending);
+#endif
+
+#endif
--- /dev/null
+#ifndef EDI_INTERRUPTS_H
+
+/* Copyright (c) 2006 Eli Gottlieb.
+ * Permission is granted to copy, distribute and/or modify this document
+ * under the terms of the GNU Free Documentation License, Version 1.2
+ * or any later version published by the Free Software Foundation;
+ * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+ * Texts. A copy of the license is included in the file entitled "COPYING". */
+
+#define EDI_INTERRUPTS_H
+
+/*! \file edi_interrupts.h
+ * \brief Declaration and description of EDI's interrupt handling class.
+ *
+ * Data structures and algorithms this header represents:
+ * DATA STRUCTURE AND ALGORITHM: INTERRUPT OBJECTS - The class EDI-INTERRUPT encapsulates the handling of machine interrupts.
+ * It is initialized with an interrupt number to handle and a handler routine to call when that interrupt occurs. Only a couple of
+ * guarantees are made to the driver regarding the runtime's implementation of interrupt handling: 1) That the driver's handler is
+ * called for every time the interrupt associated with a valid and initialized interrupt object occurs, in the order of the
+ * occurences, 2) That the runtime handle the architecture-specific (general to the entire machine, not just this device)
+ * end-of-interrupt code when the driver is called without first returning from the machine interrupt. Note that the runtime hands
+ * out interrupt numbers at its own discretion and policy. */
+
+#include "edi_objects.h"
+
+/*! \brief Macro constant containing the name of the interrupt class
+ */
+#define INTERRUPTS_CLASS "EDI-INTERRUPT"
+/*! \brief The name of EDI's interrupt-handling class.
+ *
+ * An edi_string_t holding the name of the runtime-implemented interrupt object class. It's value is "EDI-INTERRUPT". */
+#if defined(EDI_MAIN_FILE) || defined(IMPLEMENTING_EDI)
+const edi_string_t interrupts_class = INTERRUPTS_CLASS;
+#else
+extern const edi_string_t interrupts_class;
+#endif
+
+/*! \brief A pointer to an interrupt handling function.
+ *
+ * A pointer to a function called to handle interrupts. Its unsigned int32_t parameter is the interrupt number that is being
+ * handled. */
+typedef void (*interrupt_handler_t)(uint32_t interrupt_number);
+
+#ifndef IMPLEMENTING_EDI
+/*! \brief Initializes an interrupt object with an interrupt number and a pointer to a handler function.
+ *
+ * A pointer to the init_interrupt() method of class EDI-INTERRUPT. This method initializes a newly-created interrupt object with an
+ * interrupt number and a pointer to the driver's handler of type interrupt_handler_t. It can only be called once per object, and
+ * returns 1 on success, fails with -1 when the interrupt number is invalid or unacceptable to the runtime, fails with -2 when the
+ * pointer to the driver's interrupt handler is invalid, and fails with -3 for all other errors. */
+EDI_DEFVAR int32_t (*init_interrupt)(object_pointer interrupt, uint32_t interrupt_number, interrupt_handler_t handler);
+/*! \brief Get this interrupt object's interrupt number. */
+EDI_DEFVAR uint32_t (*interrupt_get_irq)(object_pointer interrupt);
+/*! \brief Set a new handler for this interrupt object. */
+EDI_DEFVAR void (*interrupt_set_handler)(object_pointer interrupt, interrupt_handler_t handler);
+/*! \brief Return from this interrupt, letting the runtime run any necessary End-Of-Interrupt code.
+ *
+ * A pointer to the interrupt_return() method of class EDI-INTERRUPT. This method returns from the interrupt designated by the
+ * calling interrupt object. If there is a machine-wide end-of-interrupt procedure and the driver was called during the handling of
+ * the machine interrupt (as opposed to delaying the handling and letting the runtime EOI), the runtime runs it during this method.
+ * This method has no return value, since once it's called control leaves the calling thread. */
+EDI_DEFVAR void (*interrupt_return)(object_pointer interrupt);
+#endif
+
+#endif
--- /dev/null
+#ifndef EDI_MEMORY_MAPPING_H
+
+/* Copyright (c) 2006 Eli Gottlieb.
+ * Permission is granted to copy, distribute and/or modify this document
+ * under the terms of the GNU Free Documentation License, Version 1.2
+ * or any later version published by the Free Software Foundation;
+ * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+ * Texts. A copy of the license is included in the file entitled "COPYING". */
+
+#define EDI_MEMORY_MAPPING_H
+
+/*! \file edi_memory_mapping.h
+ * \brief Declaration and description of EDI's class for mapping physical pages into the driver's address space.
+ *
+ * Data structures and algorithms this header represents:
+ * ALGORITHM: MEMORY MAPPINGS - Memory mapping objects of the class EDI-MEMORY-MAPPING are used to give virtual (driver-visible)
+ * addresses to sections of physical memory. These can either be memory mappings belonging to hardware devices or plain RAM which
+ * the driver wants page-aligned. A memory mapping object is initialized with the physical address for the memory mapping and the
+ * number of pages the mapping takes up, or simply the desired length of the a physically contiguous buffer in pages. The class's
+ * two methods map the section of memory into and out of the driver's virtual address space. */
+
+#include "edi_objects.h"
+
+/*! \brief The name of EDI's memory mapping class.
+ *
+ * An edi_string_t with the name of the memory mapping class, "EDI-MEMORY-MAPPING". */
+#if defined(EDI_MAIN_FILE) || defined(IMPLEMENTING_EDI)
+const edi_string_t memory_mapping_class = "EDI-MEMORY-MAPPING";
+#else
+extern const edi_string_t memory_mapping_class;
+#endif
+
+/*! \brief Flag representing Strong Uncacheable caching method. */
+#define CACHING_STRONG_UNCACHEABLE 0
+/*! \brief Flag representing Uncacheable caching method. */
+#define CACHING_UNCACHEABLE 1
+/*! \brief Flag representing Write combining caching method. */
+#define CACHING_WRITE_COMBINING 2
+/*! \brief Flag representing Write Through caching method. */
+#define CACHING_WRITE_THROUGH 3
+/*! \brief Flag representing Write Back caching method. */
+#define CACHING_WRITE_BACK 3
+/*! \brief Flag representing Write Protected caching method. */
+#define CACHING_WRITE_PROTECTED 3
+
+#ifndef IMPLEMENTING_EDI
+/*! \brief Initialize an EDI-MEMORY-MAPPING object with a physical address range.
+ *
+ * This method takes the start_physical_address of a memory mapping and the number of pages in that mapping and uses these arguments
+ * to initialize an EDI-MEMORY-MAPPING object. It can only be called once per object. It returns 1 when successful, -1 when an
+ * invalid physical address is given (one that the runtime knows is neither a physical memory mapping belonging to a device nor
+ * normal RAM), -2 when the number of pages requested is bad (for the same reasons as the starting address can be bad), and 0 for
+ * all other errors.
+ *
+ * Note that this method can't be invoked on an object which has already initialized via init_memory_mapping_with_pages(). */
+EDI_DEFVAR int32_t (*init_memory_mapping_with_address)(object_pointer mapping, data_pointer start_physical_address, uint32_t pages);
+/*! \brief Initialize an EDI-MEMORY-MAPPING object by requesting a number of new physical pages.
+ *
+ * This method takes a desired number of physical pages for a memory mapping, and uses that number to initialize an
+ * EDI-MEMORY-MAPPING object by creating a buffer of contiguous physical pages. It can only be called once per object. It returns
+ * 1 when successful, -1 when the request for pages cannot be fulfilled, and 0 for all other errors.
+ *
+ * Note that this method cannot be called if init_memory_mapping_with_address() has already been used on the given object. */
+EDI_DEFVAR int32_t (*init_memory_mapping_with_pages)(object_pointer mapping, uint32_t pages);
+/*! \brief Map the memory-mapping into this driver's visible address space.
+ *
+ * This asks the runtime to map a given memory mapping into the driver's virtual address space. Its parameter is the address of a
+ * data_pointer to place the virtual address of the mapping into. This method returns 1 on success, -1 on an invalid argument, -2
+ * for an uninitialized object, and 0 for all other errors. */
+EDI_DEFVAR int32_t (*map_in_mapping)(object_pointer mapping, data_pointer *address_mapped_to);
+/*! \brief Unmap the memory mapping from this driver's visible address space.
+ *
+ * This method tries to map the given memory mapping out of the driver's virtual address space. It returns 1 for success, -1
+ * for an uninitialized memory mapping object, -2 if the mapping isn't mapped into the driver's address space already, and 0
+ * for all other errors. */
+EDI_DEFVAR int32_t (*map_out_mapping)(object_pointer mapping);
+
+/*! \brief Set the caching flags for a memory mapping. */
+EDI_DEFVAR void (*mapping_set_caching_method)(object_pointer mapping, uint32_t caching_method);
+/*! \brief Get the current caching method for a memory mapping. */
+EDI_DEFVAR uint32_t (*mapping_get_caching_method)(object_pointer mapping);
+/*! \brief Flush write-combining buffers on CPU to make sure changes to memory mapping actually get written. Only applies to a Write Combining caching method (I think.).*/
+EDI_DEFVAR void (*flush_write_combining_mapping)(object_pointer mapping);
+#endif
+
+#endif
--- /dev/null
+#ifndef EDI_OBJECTS_H
+
+/* Copyright (c) 2006 Eli Gottlieb.
+ * Permission is granted to copy, distribute and/or modify this document
+ * under the terms of the GNU Free Documentation License, Version 1.2
+ * or any later version published by the Free Software Foundation;
+ * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+ * Texts. A copy of the license is included in the file entitled "COPYING". */
+
+#define EDI_OBJECTS_H
+
+/*! \file edi_objects.h
+ * \brief The header file for basic EDI types and the object system.
+ *
+ * This file contains declarations of EDI's primitive data types, as well as structures and functions for with the object system.
+ * It represents these data structures and algorithms:
+ *
+ * DATA STRUCTURE: THE CLASS LIST - EDI implementing runtime's must keep an internal list of classes implemented by the runtime
+ * and separate lists of classes implemented by each driver. Whoever implements a class is said to "own" that class. The
+ * internal format of this list is up to the runtime coders, but it must be possible to recreate the original list of
+ * edi_class_declaration structures the driver declared to the runtime from it. This list is declared to the runtime in an
+ * initialization function in the header edi.h. The object_class member of an edi_object_metadata structure must point to that
+ * object's class's entry in this list.
+ *
+ * ALGORITHM AND DATA STRUCTURE: CLASSES AND INHERITANCE - Classes are described using edi_class_declaration_t structures and
+ * follow very simple rules. All data is private and EDI provides no way to access instance data, so there are no member
+ * variable declarations. However, if the data isn't memory-protected (for example, driver data on the driver heap) EDI allows
+ * the possibility of pointer access to data, since runtime and driver coders could make use of that behavior. Classes may have
+ * one ancestor by declaring so in their class declaration structure, and if child methods are different then parent methods
+ * the children always override their parents. An EDI runtime must also be able to check the existence and ownership of a given
+ * class given its name in an edi_string_t.
+ *
+ * ALGORITHM: OBJECT CREATION AND DESTRUCTION - An EDI runtime should be able to call the constructor of a named class, put the
+ * resulting object_pointer into an edi_object_metadata_t and return that structure. The runtime should also be able to call an
+ * object's class's destructor when given a pointer to a valid edi_metadata_t for an already-existing object. Data equivalent
+ * to an edi_object_metadata_t should also be tracked by the runtime for every object in existence in case of sudden EDI shutdown
+ * (see edi.h).
+ *
+ * ALGORITHM: RUNTIME TYPE INFORMATION - When passed the data_pointer member of an edi_object_metadata_t to a valid object, an
+ * EDI runtime must be able to return an edi_string_t containing the name of that object's class and to return function_pointers
+ * to methods when the required information to find the correct method is given by calling a class's method getting function.*/
+
+/* If the EDI headers are linked with the standard C library, they use its type definitions. Otherwise, equivalent definitions are
+ * made.*/
+#if __STDC_VERSION__ == 199901L
+# include <stdbool.h>
+# include <stdint.h>
+#else
+# ifndef NULL
+# define NULL ((void*)0)
+# endif
+typedef unsigned char bool;
+# define true 1
+# define false 0
+typedef char int8_t;
+typedef short int16_t;
+typedef long int32_t;
+typedef long long int64_t;
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned long uint32_t;
+typedef unsigned long long uint64_t;
+#endif
+
+/*! \brief Define a variable in the header
+ */
+#ifdef EDI_MAIN_FILE
+# define EDI_DEFVAR
+#else
+# define EDI_DEFVAR extern
+#endif
+
+/*! \brief A pointer to the in-memory instance of an object.
+ *
+ * This type is sized just like a general C pointer type (whatever*) for the target architecture. It's passed as a first parameter
+ * to all methods, thus allowing EDI classes to be implemented as C++ classes and providing some protection from confusing objects
+ * with normal pointers. Equivalent to a C++ this pointer or an Object Pascal Self argument. */
+typedef void *object_pointer;
+/*! \brief A basic pointer type pointing to arbitrary data in an arbitrary location. */
+typedef void *data_pointer;
+/*! \brief A basic function pointer type.
+ *
+ * A pointer to a piece of code which can be called and return to its caller, used to distinguish between pointers to code and
+ * pointers to data. Its size is hardware-dependent. */
+typedef void (*function_pointer)(void);
+/*! \brief The length of an EDI string without its null character. */
+#define EDI_STRING_LENGTH 31
+/*! \brief A type representing a 31-character long string with a terminating NULL character at the end. All of EDI uses this type
+ * for strings.
+ *
+ * A null-terminated string type which stores characters in int8s. It allows for 31 characters in each string, with the final
+ * character being the NULL terminator. Functions which use this type must check that its final character is NULL, a string which
+ * doesn't not have this property is invalid and insecure. I (the author of EDI) know and understand that this form of a string
+ * suffers from C programmer's disease, but I can't use anything else without either making string use far buggier or dragging
+ * everyone onto a better language than C. */
+typedef int8_t edi_string_t[0x20];
+/*! \brief A type representing a pointer form of #edi_string_t suitable for function returns
+ */
+typedef int8_t *edi_string_ptr_t;
+
+/*! \var EDI_BASE_TYPES
+ * \brief A constant array of edi_string_t's holding every available EDI primitive type. */
+/*! \var EDI_TYPE_MODIFIERS
+ * \brief A constant array of edi_string_t's holding available modifiers for EDI primitive types. */
+#ifdef IMPLEMENTING_EDI
+ const edi_string_t EDI_BASE_TYPES[9] = {"void","bool","int8_t","int16_t","int32_t","int64_t","function_pointer","intreg","edi_string_t"};
+ const edi_string_t EDI_TYPE_MODIFIERS[2] = {"pointer","unsigned"};
+#else
+ //extern const edi_string_t EDI_BASE_TYPES[9] = {"void","bool","int8_t","int16_t","int32_t","int64_t","function_pointer","intreg", "edi_string_t"};
+ //extern const edi_string_t EDI_TYPE_MODIFIERS[2] = {"pointer","unsigned"};
+ extern const edi_string_t EDI_BASE_TYPES[9];
+ extern const edi_string_t EDI_TYPE_MODIFIERS[2];
+#endif
+
+/*! \struct edi_object_metadata_t
+ * \brief A packed structure holding all data to identify an object to the EDI object system. */
+typedef struct {
+ /*! \brief Points to the instance data of the object represented by this structure.
+ *
+ * An object_pointer to the object this structure refers to. The this pointer, so to speak. */
+ object_pointer object;
+ /*! \brief Points the internal record kept by the runtime describing the object's class.
+ *
+ * Points to wherever the runtime has stored the class data this object was built from. The class data doesn't need to be
+ * readable to the driver, and so this pointer can point to an arbitrary runtime-reachable location. */
+ data_pointer object_class;
+} edi_object_metadata_t;
+
+/*! \struct edi_variable_declaration_t
+ * \brief The data structure used to describe a variable declaration to the EDI object system.
+ *
+ * The data structure used to describe a variable declaration to the EDI object system. The context of the declaration depends on
+ * where the data structure appears, ie: alone, in a class declaration, in a parameter list, etc. */
+typedef struct {
+ /*! \brief The type of the declared variable.
+ *
+ * The type of the variable, which must be a valid EDI primitive type as specified in the constant EDI_BASE_TYPES and
+ * possibly modified by a modifier specified in the constant EDI_TYPE_MODIFIERS. */
+ edi_string_t type;
+ /*! \brief The name of the declared variable. */
+ edi_string_t name;
+ /*! \brief Number of array entries if this variable is an array declaration.
+ *
+ * An int32_t specifying the number of variables of 'type' in the array 'name'. For a single variable this value should
+ * simply be set to 1, for values greater than 1 a packed array of contiguous variables is being declared, and a value of 0
+ * is invalid. */
+ int32_t array_length;
+} edi_variable_declaration_t;
+
+/*! \struct edi_function_declaration_t
+ * \brief The data structure used to declare a function to the EDI object system. */
+typedef struct {
+ /*! \brief The return type of the function. The same type rules which govern variable definitions apply here. */
+ edi_string_t return_type;
+ /*! \brief The name of the declared function. */
+ edi_string_t name;
+ /*! \brief The version number of the function, used to tell different implementations of the same function apart. */
+ uint32_t version;
+ /*! \brief The number of arguments passed to the function.
+ *
+ * The number of entries in the member arguments that the object system should care about. Caring about less misses
+ * parameters to functions, caring about more results in buffer overflows. */
+ uint32_t num_arguments;
+ /*! \brief An array of the declared function's arguments.
+ *
+ * A pointer to an array num_arguments long containing edi_variable_declaration_t's for each argument to the declared
+ * function.*/
+ edi_variable_declaration_t *arguments;
+ /*!\brief A pointer to the declared function's code in memory. */
+ function_pointer code;
+} edi_function_declaration_t;
+
+/*! \brief A pointer to a function for constructing instances of a class.
+ *
+ * A pointer to a function which takes no parameters and returns an object_pointer pointing to the newly made instance of a class.
+ * It is the constructor's responsibility to allocate memory for the new object. Each EDI class needs one of these. */
+typedef object_pointer (*edi_constructor_t)(void);
+/*! \brief A pointer to a function for destroying instances of a class.
+ *
+ * A pointer to a function which takes an object_pointer as a parameter and returns void. This is the destructor counterpart to a
+ * class's edi_constructor_t, it destroys the object pointed to by its parameter and frees the object's memory. Every class must
+ * have one */
+typedef void (*edi_destructor_t)(object_pointer);
+
+/*! \brief Information the driver must give the runtime about its classes so EDI can construct them and call their methods.
+ *
+ * A structure used to declare a class to an EDI runtime so instances of it can be constructed by the EDI object system. */
+typedef struct {
+ /*! \brief The name of the class declared by the structure. */
+ edi_string_t name;
+ /*! \brief The version of the class. This number is used to tell identically named but differently
+ * implemented classes apart.*/
+ uint32_t version;
+ /*! \brief The number of methods in the 'methods' function declaration array. */
+ uint32_t num_methods;
+ /*! \brief An array of edi_function_declaration_t declaring the methods of this class. */
+ edi_function_declaration_t *methods;
+ /*! \brief Allocates the memory for a new object of the declared class and constructs the object. Absolutely required.*/
+ edi_constructor_t constructor;
+ /*! \brief Destroys the given object of the declared class and frees its memory. Absolutely required. */
+ edi_destructor_t destructor;
+ /*! \brief A pointer to another EDI class declaration structure specifying the declared class's parent class.
+ *
+ * Points to a parent class declared in another class declaration. It can be NULL to mean this class has no parent. */
+ struct edi_class_declaration_t *parent;
+} edi_class_declaration_t;
+
+/*! \brief Checks the existence of the named class.
+ *
+ * This checks for the existence on THE CLASS LIST of the class named by its edi_string_t parameter and returns a signed int32_t. If
+ * the class isn't found (ie: it doesn't exist as far as EDI is concerned) -1 is returned, if the class is owned by the driver
+ * (implemented by the driver and declared to the runtime by the driver) 0, and if the class is owned by the runtime (implemented by
+ * the runtime) 1. */
+int32_t check_class_existence(edi_string_t class_name);
+/*! \brief Constructs an object of the named class and returns its object_pointer and a data_pointer to its class data.
+ *
+ * Given a valid class name in an edi_string_t this function constructs the specified class and returns an edi_metadata_t describing
+ * the new object as detailed in OBJECT CREATION AND DESTRUCTION. If the construction fails it returns a structure full of NULL
+ * pointers. */
+edi_object_metadata_t construct_object(edi_string_t class_name);
+/*! \brief Destroys the given object using its class data.
+ *
+ * As specified in OBJECT CREATION AND DESTRUCTION this function should destroy an object when given its valid edi_metadata_t. The
+ * destruction is accomplished by calling the class's destructor. */
+void destroy_object(edi_object_metadata_t object);
+/*! \brief Obtains a function pointer to a named method of a given class.
+ *
+ * When given a valid data_pointer object_class from an edi_object_metadata_t and an edi_string_t representing the name of the
+ * desired method retrieves a function_pointer to the method's machine code in memory. If the desired method isn't found, NULL is
+ * returned. */
+function_pointer get_method_by_name(data_pointer object_class,edi_string_t method_name);
+/*! \brief Obtains a function pointer to a method given by a declaration of the given class if the class's method matches the
+ * declaration.
+ *
+ * Works just like get_method_by_name(), but by giving an edi_function_declaration_t for the desired method instead of just its name.
+ * Performs detailed checking against THE CLASS LIST to make sure that the method returned exactly matches the declaration passed
+ * in. */
+function_pointer get_method_by_declaration(data_pointer object_class,edi_function_declaration_t declaration);
+
+/* Runtime typing information. */
+/*! \brief Returns the name of the class specified by a pointer to class data.
+ *
+ * Given the data_pointer to an object's class data as stored in an edi_object_metadata_t retrieves the name of the object's class
+ * and returns it in an edi_string_t. */
+edi_string_ptr_t get_object_class(data_pointer object_class);
+/*! \brief Returns the name of a class's parent class.
+ *
+ * When given an edi_string_t with a class name in it, returns another edi_string_t containing the name of the class's parent, or an
+ * empty string. */
+edi_string_ptr_t get_class_parent(edi_string_t some_class);
+/*! \brief Returns the internal class data of a named class (if it exists) or NULL.
+ *
+ * When given an edi_string_t with a valid class name in it, returns a pointer to the runtime's internal class data for that class.
+ * Otherwise, it returns NULL. */
+data_pointer get_internal_class(edi_string_t some_class);
+
+#endif
--- /dev/null
+#ifndef EDI_PORT_IO_H
+
+/* Copyright (c) 2006 Eli Gottlieb.
+ * Permission is granted to copy, distribute and/or modify this document
+ * under the terms of the GNU Free Documentation License, Version 1.2
+ * or any later version published by the Free Software Foundation;
+ * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+ * Texts. A copy of the license is included in the file entitled "COPYING". */
+
+/* Modified by thePowersGang (John Hodge)
+ * - Surround variable definitions with an #ifdef IMPLEMENTING_EDI
+ */
+
+#define EDI_PORT_IO_H
+
+/*! \file edi_port_io.h
+ * \brief Declaration and description of EDI's port I/O class.
+ *
+ * Data structures and algorithms this header represents:
+ *
+ * DATA STRUCTURE AND ALGORITHM: PORT I/O OBJECTS - A class named "EDI-IO-PORT" is defined as an encapsulation of the port I/O
+ * used on some machine architectures. Each object of this class represents a single I/O port which can be read from and written to
+ * in various sizes. Each port can be held by one object only at a time. */
+
+#include "edi_objects.h"
+
+/*! \brief Macro to create methods for reading from ports.
+ *
+ * This macro creates four similar methods, differing in the size of the type they read from the I/O port held by the object. Their
+ * parameter is a pointer to the output type, which is filled with the value read from the I/O port. They return 1 for success, -1
+ * for an uninitialized I/O port object, and 0 for other errors. */
+#define port_read_method(type,name) int32_t (*name)(object_pointer port_object, type *out)
+/*! \brief Macro to create methods for writing to ports.
+ *
+ * This macro creates four more similar methods, differing in the size of the type they write to the I/O port held by the object.
+ * Their parameter is the value to write to the port. They return 1 for success, -1 for an uninitialized I/O port object and 0 for
+ * other errors. */
+#define port_write_method(type,name) int32_t (*name)(object_pointer port_object, type in)
+
+/*! \brief Name of EDI I/O port class. (Constant)
+ *
+ * A CPP constant with the value of #io_port_class */
+#define IO_PORT_CLASS "EDI-IO-PORT"
+/*! \brief Name of EDI I/O port class.
+ *
+ * An edi_string_t containing the class name "EDI-IO-PORT". */
+#if defined(EDI_MAIN_FILE) || defined(IMPLEMENTING_EDI)
+const edi_string_t io_port_class = IO_PORT_CLASS;
+#else
+extern const edi_string_t io_port_class;
+#endif
+
+#ifndef IMPLEMENTING_EDI
+/*! \brief int32_t EDI-IO-PORT.init_io_port(unsigned int16_t port);
+ *
+ * This method takes an unsigned int16_t representing a particular I/O port and initializes the invoked EDI-IO-PORT object with it.
+ * The method returns 1 if successful, -1 if the I/O port could not be obtained for the object, and 0 for all other errors. */
+EDI_DEFVAR int32_t (*init_io_port)(object_pointer port_object, uint16_t port);
+/*! \brief Get the port number from a port object. */
+EDI_DEFVAR uint16_t (*get_port_number)(object_pointer port);
+/*! \brief Method created by port_read_method() in order to read bytes (int8s) from I/O ports. */
+EDI_DEFVAR int32_t (*read_byte_io_port)(object_pointer port_object, int8_t *out);
+/*! \brief Method created by port_read_method() in order to read words (int16s) from I/O ports. */
+EDI_DEFVAR int32_t (*read_word_io_port)(object_pointer port_object, int16_t *out);
+/*! \brief Method created by port_read_method() in order to read longwords (int32s) from I/O ports. */
+EDI_DEFVAR int32_t (*read_long_io_port)(object_pointer port_object, int32_t *out);
+/*! \brief Method created by port_read_method() in order to read long longwords (int64s) from I/O ports. */
+EDI_DEFVAR int32_t (*read_longlong_io_port)(object_pointer port_object,int64_t *out);
+/*! \brief Method of EDI-IO-PORT to read long strings of data from I/O ports.
+ *
+ * Reads arbitrarily long strings of data from the given I/O port. Returns 1 for success, -1 for an uninitialized port object, -2
+ * for a bad pointer to the destination buffer, and 0 for all other errors. */
+EDI_DEFVAR int32_t (*read_string_io_port)(object_pointer port_object, uint32_t data_length, uint8_t *out);
+/*! \brief Method created by port_write_method() in order to write bytes (int8s) to I/O ports. */
+EDI_DEFVAR int32_t (*write_byte_io_port)(object_pointer port_object, int8_t in);
+/*! \brief Method created by port_write_method() in order to write words (int16s) to I/O ports. */
+EDI_DEFVAR int32_t (*write_word_io_port)(object_pointer port_object, int16_t in);
+/*! \brief Method created by port_write_method() in order to write longwords (int32s) to I/O ports. */
+EDI_DEFVAR int32_t (*write_long_io_port)(object_pointer port_object, int32_t in);
+/*! \brief Method created by port_write_method() in order to write long longwords (int64s) to I/O ports. */
+EDI_DEFVAR int32_t (*write_longlong_io_port)(object_pointer port_object, int64_t in);
+/*! \brief Method of EDI-IO-PORT to write long strings of data to I/O ports.
+ *
+ * Writes arbitrarily long strings of data to the given I/O port. Returns 1 for success, -1 for an uninitialized port object, -2
+ * for a bad pointer to the source buffer, and 0 for all other errors. */
+EDI_DEFVAR int32_t (*write_string_io_port)(object_pointer port_object, uint32_t data_length, uint8_t *in);
+
+#endif // defined(IMPLEMENTING_EDI)
+
+#endif
--- /dev/null
+#ifndef EDI_PTHREADS
+
+/* Copyright (c) 2006 Eli Gottlieb.
+ * Permission is granted to copy, distribute and/or modify this document
+ * under the terms of the GNU Free Documentation License, Version 1.2
+ * or any later version published by the Free Software Foundation;
+ * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+ * Texts. A copy of the license is included in the file entitled "COPYING". */
+
+#define EDI_PTHREADS
+/*!\file edi_pthreads.h
+ * \brief A basic subset of POSIX Threads functionality, providing threading and thread synchronization.
+ *
+ * A very basic POSIX Threads interface. Note that pthreads are not a class, because none of these calls really gels with
+ * object-oriented programming. Also, if drivers aren't processes or threads under the implementing operating system a small
+ * threading system must be implemented in-runtime just to multiplex the pthreads of EDI drivers. Sorry about that.
+ *
+ * Data structures and algorithms this header represents:
+ *
+ * ALGORITHM AND DATA STRUCTURE: POSIX Threading - The runtime must provide enough of a POSIX threading interface to implement
+ * the calls described here. The actual multithreading must be performed by the runtime, and the runtime can implement that
+ * multithreading however it likes as long as the given POSIX Threads subset works. There is, however, a caveat: since the runtime
+ * calls the driver like it would a library, the driver must perceive all calls made to it by the runtime as running under one thread.
+ * From this thread the driver can create others. Such behavior is a quirk of EDI, and does not come from the POSIX standard.
+ * However, it is necessary to provide the driver with a thread for its own main codepaths. For further details on a given POSIX
+ * Threading routine, consult its Unix manual page. */
+
+#include "edi_objects.h"
+
+/* Placeholder type definitions. Users of the PThreads interface only ever need to define pointers to these types. */
+/*!\brief Opaque POSIX Threading thread attribute type. */
+typedef void pthread_attr_t;
+/*!\brief Opaque POSIX Threading mutex (mutual exclusion semaphore) type. */
+typedef void pthread_mutex_t;
+/*!\brief Opaque POSIX Threading mutex attribute type. */
+typedef void pthread_mutex_attr_t;
+
+/*!\struct sched_param
+ * \brief POSIX Threading scheduler parameters for a thread. */
+typedef struct {
+ /*!\brief The priority of the thread. */
+ int32_t sched_priority;
+} sched_param;
+
+/*!\brief POSIX Threading thread identifier. */
+typedef uint32_t pthread_t;
+/*!\brief POSIX Threading thread function type.
+ *
+ * A function pointer to a thread function, with the required signature of a thread function. A thread function takes one untyped
+ * pointer as an argument and returns an untyped pointer. Such a function is a thread's main routine: it's started with the thread,
+ * and the thread exits if it returns. */
+typedef void *(*pthread_function_t)(void*);
+
+/*!\brief Insufficient resources. */
+#define EAGAIN -1
+/*!\brief Invalid parameter. */
+#define EINVAL -2
+/*!\brief Permission denied. */
+#define EPERM -3
+/*!\brief Operation not supported. */
+#define ENOTSUP -4
+/*!\brief Priority scheduling for POSIX/multiple schedulers is not implemented. */
+#define ENOSYS -5
+/*!\brief Out of memory. */
+#define ENOMEM -6
+/*!\brief Deadlock. Crap. */
+#define EDEADLK -7
+/*!\brief Busy. Mutex already locked. */
+#define EBUSY -8
+
+/*!\brief Scheduling policy for regular, non-realtime scheduling. The default. */
+#define SCHED_OTHER 0
+/*!\brief Real-time, first-in first-out scheduling policy. Requires special (superuser, where such a thing exists) permissions. */
+#define SCHED_FIFO 1
+/*!\brief Real-time, round-robin scheduling policy. Requires special (superuser, where such a thing exists) permissions. */
+#define SCHED_RR 0
+
+/*!\brief Creates a new thread with the given attributes, thread function and arguments, giving back the thread ID of the new
+ * thread.
+ *
+ * pthread_create() creates a new thread of control that executes concurrently with the calling thread. The new thread applies the
+ * function start_routine, passing it arg as its argument. The attr argument specifies thread attributes to apply to the new thread;
+ * it can also be NULL for the default thread attributes (joinable with default scheduling policy). On success this function returns
+ * 0 and places the identifier of the new thread into thread_id. On an error, pthread_create() can return EAGAIN if insufficient
+ * runtime resources are available to create the requested thread, EINVAL a value specified by attributes is invalid, or EPERM if the
+ * caller doesn't have permissions to set the given attributes.
+ *
+ * For further information: man 3 pthread_create */
+int32_t pthread_create(pthread_t *thread_id, const pthread_attr_t *attributes, pthread_function_t thread_function, void *arguments);
+/*!\brief Terminates the execution of the calling thread. The thread's exit code with by status, and this routine never returns. */
+void pthread_exit(void *status);
+/*!\brief Returns the thread identifier of the calling thread. */
+pthread_t pthread_self();
+/*!\brief Compares two thread identifiers.
+ *
+ * Determines of the given two thread identifiers refer to the same thread. If so, returns non-zero. Otherwise, 0 is returned. */
+int32_t pthread_equal(pthread_t thread1, pthread_t thread2);
+/*!\brief Used by the calling thread to relinquish use of the processor. The thread then waits in the run queue to be scheduled
+ * again. */
+void pthread_yield();
+
+/*!\brief Gets the scheduling policy of the given attributes.
+ *
+ * Places the scheduling policy for attributes into policy. Returns 0 on success, EINVAL if attributes was invalid, and ENOSYS if
+ * priority scheduling/multiple scheduler support is not implemented. */
+int32_t pthread_attr_getschedpolicy(const pthread_attr_t *attributes, int32_t *policy);
+/*!\brief Sets the scheduling policy of the given attributes.
+ *
+ * Requests a switch of scheduling policy to policy for the given attributes. Can return 0 for success, EINVAL if the given policy
+ * is not one of SCHED_OTHER, SCHED_FIFO or SCHED_RR or ENOTSUP if policy is either SCHED_FIFO or SCHED_RR and the driver is not
+ * running with correct privileges. */
+int32_t pthread_attr_setschedpolicy(pthread_attr_t *attributes, int32_t policy);
+
+/*!\brief Gets the scheduling paramaters (priority) from the given attributes.
+ *
+ * On success, stores scheduling parameters in param from attributes, and returns 0. Otherwise, returns non-zero error code, such
+ * as EINVAL if the attributes object is invalid. */
+int32_t pthread_attr_getschedparam(const pthread_attr_t *attributes, sched_param *param);
+/*!\brief Sets the scheduling parameters (priority) of the given attributes.
+ *
+ * Requests that the runtime set the scheduling parameters (priority) of attributes from param. Returns 0 for success, EINVAL for an
+ * invalid attributes object, ENOSYS when multiple schedulers/priority scheduling is not implemented, and ENOTSUP when the value of
+ * param isn't supported/allowed. */
+int32_t pthread_attr_setschedparam(pthread_attr_t *attributes, const sched_param *param);
+
+/*!\brief The thread obtains its scheduling properties explicitly from its attributes structure. */
+#define PTHREAD_EXPLICIT_SCHED 1
+/*!\brief The thread inherits its scheduling properties from its parent thread. */
+#define PTHREAD_INHERIT_SCHED 0
+
+/*!\brief Returns the inheritsched attribute of the given attributes.
+ *
+ * On success, returns 0 and places the inheritsched attribute from attributes into inherit. This attribute specifies where the
+ * thread's scheduling properites shall come from, and can be set to PTHREAD_EXPLICIT_SCHED or PTHREAD_INHERIT_SCHED. On failure it
+ * returns EINVAL if attributes was invalid or ENOSYS if multiple schedulers/priority scheduling isn't implemented. */
+int32_t pthread_attr_getinheritsched(const pthread_attr_t *attributes, int32_t *inherit);
+/*!\brief Sets the inheritsched attribute of the given attributes.
+ *
+ * On success, places inherit into the inheritsched attribute of attributes and returns 0. inherit must either contain
+ * PTHREAD_EXPLICIT_SCHED or PTHREAD_INHERIT_SCHED. On failure, this routine returns EINVAL if attributes is invalid, ENOSYS when
+ * multiple schedulers/priority scheduling isn't implemented, and ENOSUP if the inheritsched attribute isn't supported. */
+int32_t pthread_attr_setinheritsched(pthread_attr_t *attributes, int32_t inherit);
+
+/*!\brief Creates a new POSIX Threads mutex, which will initially be unlocked.
+ *
+ * Creates a new mutex with the given attributes. If attributes is NULL, the default attributes will be used. The mutex starts out
+ * unlocked. On success, the new mutex resides in the mutex structure pointed to by mutex, and this routine routines 0. On failure,
+ * it returns EAGAIN if the system lacked sufficient non-memory resources to initialize the mutex, EBUSY if the given mutex is
+ * already initialized and in use, EINVAL if either parameter is invalid, and ENOMEM if the system lacks the memory for a new
+ * mutex. Note: All EDI mutexes are created with the default attributes, and are of type PTHREAD_MUTEX_ERRORCHECK. This means
+ * undefined behavior can never result from an badly placed function call. */
+int32_t pthread_mutex_init (pthread_mutex_t *mutex, const pthread_mutex_attr_t *attributes);
+/*!\brief Locks the given mutex.
+ *
+ * Locks the given mutex. If the mutex is already locked, blocks the calling thread until it can acquire the lock. When this
+ * routine returns successfully, it will return 0 and the calling thread will own the lock of the mutex. If the call fails, it can
+ * return EINVAL when mutex is invalid or EDEADLK if the calling thread already owns the mutex. */
+int32_t pthread_mutex_lock(pthread_mutex_t *mutex);
+/*!\brief Unlocks the given mutex.
+ *
+ * Unlocks the given mutex, returning 0 on success. On failure, it can return EINVAL when mutex is invalid or EPERM when the
+ * calling thread doesn't own the mutex. */
+int32_t pthread_mutex_unlock(pthread_mutex_t *mutex);
+/*!\brief Tries to lock the given mutex, returning immediately even if the mutex is already locked.
+ *
+ * Attempts to lock the given mutex, but returns immediately if it can't acquire a lock. Returns 0 when it has acquired a lock,
+ * EBUSY if the mutex is already locked, or EINVAL if mutex is invalid. */
+int32_t pthread_mutex_trylock(pthread_mutex_t *mutex);
+/*!\brief Destroys the given mutex, or at least the internal structure of it.
+ *
+ * Deletes the given mutex, making mutex invalid until it should be initialized by pthread_mutex_init(). Returns 0 on success,
+ * EINVAL when mutex is invalid, or EBUSY when mutex is locked or referenced by another thread. */
+int32_t pthread_mutex_destroy (pthread_mutex_t *mutex);
+
+#endif
--- /dev/null
+#ifndef HELPERS_H
+
+#define HELPERS_H
+
+#include <edi.h>
+
+// Locally Defined
+bool edi_string_equal(edi_string_t x,edi_string_t y);
+bool descends_from(data_pointer object_class,edi_string_t desired_class);
+data_pointer get_actual_class(edi_string_t ancestor,int32_t num_objects,edi_object_metadata_t *objects);
+
+// Local Copy/set
+void *memcpyd(void *dest, void *src, unsigned int count);
+
+// Implementation Defined Common functions
+void *memcpy(void *dest, void *src, unsigned int count);
+void *memmove(void *dest, void *src, unsigned int count);
+void *realloc(void *ptr, unsigned int size);
+
+#endif
--- /dev/null
+/*
+ * AcessOS EDI Interface
+ * - IRQ Class
+ *
+ * By John Hodge (thePowersGang)
+ *
+ * This file has been released into the public domain.
+ * You are free to use it as you wish.
+ */
+#include "edi/edi.h"
+
+// === TYPES ===
+typedef struct {
+ uint16_t State; // 0: Unallocated, 1: Allocated, 2: Initialised, (Bit 0x8000 set if in heap)
+ uint16_t Num;
+ interrupt_handler_t Handler;
+} tEdiIRQ;
+
+// === PROTOTYPES ===
+void EDI_Int_IRQ_Handler(tRegs *Regs);
+
+// === GLOBALS ===
+tEdiIRQ gEdi_IRQObjects[16];
+
+// === FUNCTIONS ===
+/**
+ * \fn object_pointer Edi_Int_IRQ_Construct(void)
+ * \brief Creates a new IRQ Object
+ * \return Pointer to object
+ */
+object_pointer Edi_Int_IRQ_Construct(void)
+{
+ int i;
+ // Search for a free irq
+ for( i = 0; i < 16; i ++ )
+ {
+ if(gEdi_IRQObjects[i].State) continue;
+ gEdi_IRQObjects[i].State = 1;
+ gEdi_IRQObjects[i].Num = 0;
+ gEdi_IRQObjects[i].Handler = NULL;
+ return &gEdi_IRQObjects[i];
+ }
+ return NULL;
+}
+
+/**
+ * \fn void Edi_Int_IRQ_Destruct(object_pointer Object)
+ * \brief Destruct an IRQ Object
+ * \param Object Object to destroy
+ */
+void Edi_Int_IRQ_Destruct(object_pointer Object)
+{
+ tEdiIRQ *obj;
+
+ VALIDATE_PTR(Object,);
+ obj = GET_DATA(Object);
+
+ if( !obj->State ) return;
+
+ if( obj->Handler )
+ irq_uninstall_handler( obj->Num );
+
+ if( obj->State & 0x8000 ) { // If in heap, free
+ free(Object);
+ } else { // Otherwise, mark as unallocated
+ obj->State = 0;
+ }
+}
+
+/**
+ * \fn int32_t Edi_Int_IRQ_InitInt(object_pointer Object, uint16_t Num, interrupt_handler_t Handler)
+ * \brief Initialises an IRQ
+ * \param Object Object Pointer (this)
+ * \param Num IRQ Number to use
+ * \param Handler Callback for IRQ
+ */
+int32_t Edi_Int_IRQ_InitInt(object_pointer Object, uint16_t Num, interrupt_handler_t Handler)
+{
+ tEdiIRQ *obj;
+
+ //LogF("Edi_Int_IRQ_InitInt: (Object=0x%x, Num=%i, Handler=0x%x)\n", Object, Num, Handler);
+
+ VALIDATE_PTR(Object,0);
+ obj = GET_DATA(Object);
+
+ if( !obj->State ) return 0;
+
+ if(Num > 15) return 0;
+
+ // Install the IRQ if a handler is passed
+ if(Handler) {
+ if( !irq_install_handler(Num, Edi_Int_IRQ_Handler) )
+ return 0;
+ obj->Handler = Handler;
+ }
+
+ obj->Num = Num;
+ obj->State &= ~0x3FFF;
+ obj->State |= 2; // Set initialised flag
+ return 1;
+}
+
+/**
+ * \fn uint16_t Edi_Int_IRQ_GetInt(object_pointer Object)
+ * \brief Returns the irq number associated with the object
+ * \param Object IRQ Object to get number from
+ * \return IRQ Number
+ */
+uint16_t Edi_Int_IRQ_GetInt(object_pointer Object)
+{
+ tEdiIRQ *obj;
+
+ VALIDATE_PTR(Object,0);
+ obj = GET_DATA(Object);
+
+ if( !obj->State ) return 0;
+ return obj->Num;
+}
+
+/**
+ * \fn void EDI_Int_IRQ_SetHandler(object_pointer Object, interrupt_handler_t Handler)
+ * \brief Set the IRQ handler for an IRQ object
+ * \param Object IRQ Object to alter
+ * \param Handler Function to use as handler
+ */
+void EDI_Int_IRQ_SetHandler(object_pointer Object, interrupt_handler_t Handler)
+{
+ tEdiIRQ *obj;
+
+ // Get Data Pointer
+ VALIDATE_PTR(Object,);
+ obj = GET_DATA(Object);
+
+ // Sanity Check arguments
+ if( !obj->State ) return ;
+
+ // Only register the mediator if it is not already
+ if( Handler && !obj->Handler )
+ if( !irq_install_handler(obj->Num, Edi_Int_IRQ_Handler) )
+ return ;
+ obj->Handler = Handler;
+}
+
+/**
+ * \fn void EDI_Int_IRQ_Return(object_pointer Object)
+ * \brief Return from interrupt
+ * \param Object IRQ Object
+ * \note Due to the structure of acess interrupts, this is a dummy
+ */
+void EDI_Int_IRQ_Return(object_pointer Object)
+{
+}
+
+/**
+ * \fn void Edi_Int_IRQ_Handler(struct regs *Regs)
+ * \brief EDI IRQ Handler - Calls the handler
+ * \param Regs Register state at IRQ call
+ */
+void Edi_Int_IRQ_Handler(struct regs *Regs)
+{
+ int i;
+ for( i = 0; i < 16; i ++ )
+ {
+ if(!gEdi_IRQObjects[i].State) continue; // Unused, Skip
+ if(gEdi_IRQObjects[i].Num != Regs->int_no) continue; // Another IRQ, Skip
+ if(!gEdi_IRQObjects[i].Handler) continue; // No Handler, Skip
+ gEdi_IRQObjects[i].Handler( Regs->int_no ); // Call Handler
+ return;
+ }
+}
+
+
+// === CLASS DECLARATION ===
+static edi_function_declaration_t scEdi_Int_Functions_IRQ[] = {
+ {"int32_t", "init_interrupt", 1, 3, NULL, //scEdi_Int_Variables_IO[0],
+ (function_pointer)Edi_Int_IRQ_InitInt
+ },
+ {"uint32_t", "interrupt_get_irq", 1, 1, NULL, //scEdi_Int_Variables_IO[1],
+ (function_pointer)Edi_Int_IRQ_GetInt
+ },
+ {"void", "interrupt_set_handler", 1, 2, NULL, //scEdi_Int_Variables_IO[2],
+ (function_pointer)Edi_Int_IRQ_GetInt
+ },
+ {"void", "interrupt_return", 1, 1, NULL, //scEdi_Int_Variables_IO[3],
+ (function_pointer)Edi_Int_IRQ_GetInt
+ }
+ };
+static edi_class_declaration_t scEdi_Int_Class_IRQ =
+ {
+ INTERRUPTS_CLASS, 1, 12,
+ scEdi_Int_Functions_IRQ,
+ Edi_Int_IRQ_Construct,
+ Edi_Int_IRQ_Destruct,
+ NULL
+ };
--- /dev/null
+/*
+ * AcessOS EDI Interface
+ * - IO Port Class
+ *
+ * By John Hodge (thePowersGang)
+ *
+ * This file has been released into the public domain.
+ * You are free to use it as you wish.
+ */
+#include "edi/edi.h"
+
+// === TYPES ===
+typedef struct {
+ uint16_t State; // 0: Unallocated, 1: Allocated, 2: Initialised, (Bit 0x8000 set if in heap)
+ uint16_t Num;
+} tEdiPort;
+
+// === GLOBALS ===
+#define NUM_PREALLOC_PORTS 128
+tEdiPort gEdi_PortObjects[NUM_PREALLOC_PORTS];
+
+// === FUNCTIONS ===
+/**
+ * \fn object_pointer Edi_Int_IO_Construct(void)
+ * \brief Creates a new IO Port Object
+ * \return Pointer to object
+ */
+object_pointer Edi_Int_IO_Construct(void)
+{
+ tEdiPort *ret;
+ int i;
+ // Search for a free preallocated port
+ for( i = 0; i < NUM_PREALLOC_PORTS; i ++ )
+ {
+ if(gEdi_PortObjects[i].State) continue;
+ gEdi_PortObjects[i].State = 1;
+ gEdi_PortObjects[i].Num = 0;
+ return &gEdi_PortObjects[i];
+ }
+ // Else, use heap space
+ ret = malloc( sizeof(tEdiPort) );
+ ret->State = 0x8001;
+ ret->Num = 0;
+ return ret;
+}
+
+/**
+ * \fn void Edi_Int_IO_Destruct(object_pointer Object)
+ * \brief Destruct an IO Port Object
+ * \param Object Object to destroy
+ */
+void Edi_Int_IO_Destruct(object_pointer Object)
+{
+ tEdiPort *obj;
+ // Get Data Pointer
+ VALIDATE_PTR(Object,);
+ obj = GET_DATA(Object);
+
+ if(obj->State & 0x8000) { // If in heap, free
+ free(Object);
+ } else { // Otherwise, mark as unallocated
+ obj->State = 0;
+ }
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_InitPort(object_pointer Object, uint16_t Port)
+ * \brief Initialises an IO Port
+ * \param Object Object Pointer (this)
+ * \param Port Port Number to use
+ */
+int32_t Edi_Int_IO_InitPort(object_pointer Object, uint16_t Port)
+{
+ tEdiPort *obj;
+ // Get Data Pointer
+ VALIDATE_PTR(Object, 0);
+ obj = GET_DATA(Object);
+
+ if( !obj->State ) return 0;
+ obj->Num = Port;
+ obj->State &= ~0x3FFF;
+ obj->State |= 2; // Set initialised flag
+ return 1;
+}
+
+/**
+ * \fn uint16_t Edi_Int_IO_GetPortNum(object_pointer Object)
+ * \brief Returns the port number associated with the object
+ * \param Object Port Object to get number from
+ * \return Port Number
+ */
+uint16_t Edi_Int_IO_GetPortNum(object_pointer Object)
+{
+ tEdiPort *obj;
+ // Get Data Pointer
+ VALIDATE_PTR(Object, 0);
+ obj = GET_DATA(Object);
+ // Check if valid
+ if( !obj->State ) return 0;
+ // Return Port No
+ return obj->Num;
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_ReadByte(object_pointer Object, uint8_t *out)
+ * \brief Read a byte from an IO port
+ * \param Object Port Object
+ * \param out Pointer to put read data
+ */
+int32_t Edi_Int_IO_ReadByte(object_pointer Object, uint8_t *out)
+{
+ tEdiPort *obj;
+ // Get Data Pointer
+ VALIDATE_PTR(Object, 0);
+ obj = GET_DATA(Object);
+
+ if( !obj->State ) return 0;
+ if( obj->State & 1 ) return -1; // Unintialised
+
+ __asm__ __volatile__ ( "inb %%dx, %%al" : "=a" (*out) : "d" ( obj->Num ) );
+
+ return 1;
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_ReadWord(object_pointer Object, uint16_t *out)
+ * \brief Read a word from an IO port
+ * \param Object Port Object
+ * \param out Pointer to put read data
+ */
+int32_t Edi_Int_IO_ReadWord(object_pointer Object, uint16_t *out)
+{
+
+ tEdiPort *obj;
+ // Get Data Pointer
+ VALIDATE_PTR(Object, 0);
+ obj = GET_DATA(Object);
+ if( !obj->State ) return 0;
+ if( obj->State & 1 ) return -1; // Unintialised
+
+ __asm__ __volatile__ ( "inw %%dx, %%ax" : "=a" (*out) : "d" ( obj->Num ) );
+
+ return 1;
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_ReadDWord(object_pointer Object, uint32_t *out)
+ * \brief Read a double word from an IO port
+ * \param Object Port Object
+ * \param out Pointer to put read data
+ */
+int32_t Edi_Int_IO_ReadDWord(object_pointer Object, uint32_t *out)
+{
+
+ tEdiPort *obj;
+ // Get Data Pointer
+ VALIDATE_PTR(Object, 0);
+ obj = GET_DATA(Object);
+ if( !obj->State ) return 0;
+ if( obj->State & 1 ) return -1; // Unintialised
+
+ __asm__ __volatile__ ( "inl %%dx, %%eax" : "=a" (*out) : "d" ( obj->Num ) );
+
+ return 1;
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_ReadQWord(object_pointer Object, uint64_t *out)
+ * \brief Read a quad word from an IO port
+ * \param Object Port Object
+ * \param out Pointer to put read data
+ */
+int32_t Edi_Int_IO_ReadQWord(object_pointer Object, uint64_t *out)
+{
+ uint32_t *out32 = (uint32_t*)out;
+ tEdiPort *obj;
+ // Get Data Pointer
+ VALIDATE_PTR(Object, 0);
+ obj = GET_DATA(Object);
+ if( !obj->State ) return 0;
+ if( obj->State & 1 ) return -1; // Unintialised
+
+ __asm__ __volatile__ ( "inl %%dx, %%eax" : "=a" (*out32) : "d" ( obj->Num ) );
+ __asm__ __volatile__ ( "inl %%dx, %%eax" : "=a" (*(out32+1)) : "d" ( obj->Num+4 ) );
+
+ return 1;
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_ReadString(object_pointer Object, uint32_t Length, uint8_t *out)
+ * \brief Read a byte from an IO port
+ * \param Object Port Object
+ * \param Length Number of bytes to read
+ * \param out Pointer to put read data
+ */
+int32_t Edi_Int_IO_ReadString(object_pointer Object, uint32_t Length, uint8_t *out)
+{
+ tEdiPort *obj;
+ // Get Data Pointer
+ VALIDATE_PTR(Object, 0);
+ obj = GET_DATA(Object);
+ if( !obj->State ) return 0;
+ if( obj->State & 1 ) return -1; // Unintialised
+
+ __asm__ __volatile__ ( "rep insb" : : "c" (Length), "D" (out), "d" ( obj->Num ) );
+
+ return 1;
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_WriteByte(object_pointer Object, uint8_t in)
+ * \brief Write a byte from an IO port
+ * \param Object Port Object
+ * \param in Data to write
+ */
+int32_t Edi_Int_IO_WriteByte(object_pointer Object, uint8_t in)
+{
+ tEdiPort *obj;
+ // Get Data Pointer
+ VALIDATE_PTR(Object, 0);
+ obj = GET_DATA(Object);
+ if( !obj->State ) return 0;
+ if( obj->State & 1 ) return -1; // Unintialised
+
+ __asm__ __volatile__ ( "outb %%al, %%dx" : : "a" (in), "d" ( obj->Num ) );
+
+ return 1;
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_WriteWord(object_pointer Object, uint16_t in)
+ * \brief Write a word from an IO port
+ * \param Object Port Object
+ * \param in Data to write
+ */
+int32_t Edi_Int_IO_WriteWord(object_pointer Object, uint16_t in)
+{
+ tEdiPort *obj;
+ // Get Data Pointer
+ VALIDATE_PTR(Object, 0);
+ obj = GET_DATA(Object);
+ if( !obj->State ) return 0;
+ if( obj->State & 1 ) return -1; // Unintialised
+
+ __asm__ __volatile__ ( "outw %%ax, %%dx" : : "a" (in), "d" ( obj->Num ) );
+
+ return 1;
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_WriteDWord(object_pointer Object, uint32_t in)
+ * \brief Write a double word from an IO port
+ * \param Object Port Object
+ * \param in Data to write
+ */
+int32_t Edi_Int_IO_WriteDWord(object_pointer Object, uint32_t in)
+{
+ tEdiPort *obj;
+ // Get Data Pointer
+ VALIDATE_PTR(Object, 0);
+ obj = GET_DATA(Object);
+ if( !obj->State ) return 0;
+ if( obj->State & 1 ) return -1; // Unintialised
+
+ __asm__ __volatile__ ( "outl %%eax, %%dx" : : "a" (in), "d" ( obj->Num ) );
+
+ return 1;
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_WriteQWord(object_pointer Object, uint64_t in)
+ * \brief Write a quad word from an IO port
+ * \param Object Port Object
+ * \param in Data to write
+ */
+int32_t Edi_Int_IO_WriteQWord(object_pointer Object, uint64_t in)
+{
+ uint32_t *in32 = (uint32_t*)∈
+ tEdiPort *obj;
+ // Get Data Pointer
+ VALIDATE_PTR(Object, 0);
+ obj = GET_DATA(Object);
+ if( !obj->State ) return 0;
+ if( obj->State & 1 ) return -1; // Unintialised
+
+ __asm__ __volatile__ ( "outl %%eax, %%dx" : : "a" (*in32), "d" ( obj->Num ) );
+ __asm__ __volatile__ ( "outl %%eax, %%dx" : : "a" (*(in32+1)), "d" ( obj->Num+4 ) );
+
+ return 1;
+}
+
+/**
+ * \fn int32_t Edi_Int_IO_WriteString(object_pointer Object, uint32_t Length, uint8_t *in)
+ * \brief Read a byte from an IO port
+ * \param Object Port Object
+ * \param Length Number of bytes to write
+ * \param in Pointer to of data to write
+ */
+int32_t Edi_Int_IO_WriteString(object_pointer Object, uint32_t Length, uint8_t *in)
+{
+ tEdiPort *obj;
+ // Get Data Pointer
+ VALIDATE_PTR(Object, 0);
+ obj = GET_DATA(Object);
+ if( !obj->State ) return 0;
+ if( obj->State & 1 ) return -1; // Unintialised
+
+ __asm__ __volatile__ ( "rep outsb" : : "c" (Length), "D" (in), "d" ( obj->Num ) );
+
+ return 1;
+}
+
+// === CLASS DECLARATION ===
+/*static edi_variable_declaration_t *scEdi_Int_Variables_IO[] = {
+ {
+ {"pointer", "port_object", 0},
+ {"uint16_t", "port", 0}
+ },
+ {
+ {"pointer", "port_object", 0}
+ },
+ {
+ {"pointer", "port_object", 0},
+ {"pointer int8_t", "out", 0}
+ }
+};*/
+static edi_function_declaration_t scEdi_Int_Functions_IO[] = {
+ {"int32_t", "init_io_port", 1, 2, NULL, //scEdi_Int_Variables_IO[0],
+ (function_pointer)Edi_Int_IO_InitPort
+ },
+ {"uint16_t", "get_port_number", 1, 1, NULL, //scEdi_Int_Variables_IO[1],
+ (function_pointer)Edi_Int_IO_GetPortNum
+ },
+ {"int32_t", "read_byte_io_port", 1, 2, NULL, //scEdi_Int_Variables_IO[2],
+ (function_pointer)Edi_Int_IO_ReadByte
+ },
+ {"int32_t", "read_word_io_port", 1, 2, NULL/*{
+ {"pointer", "port_object", 0},
+ {"pointer int16_t", "out", 0}
+ }*/,
+ (function_pointer)Edi_Int_IO_ReadWord
+ },
+ {"int32_t", "read_long_io_port", 1, 2, NULL/*{
+ {"pointer", "port_object", 0},
+ {"pointer int32_t", "out", 0}
+ }*/,
+ (function_pointer)Edi_Int_IO_ReadDWord
+ },
+ {"int32_t", "read_longlong_io_port", 1, 2, NULL/*{
+ {"pointer", "port_object", 0},
+ {"pointer int64_t", "out", 0}
+ }*/,
+ (function_pointer)Edi_Int_IO_ReadQWord
+ },
+ {"int32_t", "read_string_io_port", 1, 3, NULL/*{
+ {"pointer", "port_object", 0},
+ {"int32_T", "data_length", 0},
+ {"pointer int64_t", "out", 0}
+ }*/,
+ (function_pointer)Edi_Int_IO_ReadString
+ },
+
+ {"int32_t", "write_byte_io_port", 1, 2, NULL/*{
+ {"pointer", "port_object", 0},
+ {"int8_t", "in", 0}
+ }*/,
+ (function_pointer)Edi_Int_IO_WriteByte},
+ {"int32_t", "write_word_io_port", 1, 2, NULL/*{
+ {"pointer", "port_object", 0},
+ {"int16_t", "in", 0}
+ }*/,
+ (function_pointer)Edi_Int_IO_WriteWord},
+ {"int32_t", "write_long_io_port", 1, 2, NULL/*{
+ {"pointer", "port_object", 0},
+ {"int32_t", "in", 0}
+ }*/,
+ (function_pointer)Edi_Int_IO_WriteDWord},
+ {"int32_t", "write_longlong_io_port", 1, 2, NULL/*{
+ {"pointer", "port_object", 0},
+ {"int64_t", "in", 0}
+ }*/,
+ (function_pointer)Edi_Int_IO_WriteQWord}
+ };
+static edi_class_declaration_t scEdi_Int_Class_IO =
+ {
+ IO_PORT_CLASS, 1, 12,
+ scEdi_Int_Functions_IO,
+ Edi_Int_IO_Construct,
+ Edi_Int_IO_Destruct,
+ NULL
+ };
--- /dev/null
+/*
+ * Acess2 EDI Layer
+ */
+#define DEBUG 0
+#define VERSION ((0<<8)|1)
+#include <acess.h>
+#include <modules.h>
+#include <fs_devfs.h>
+#define IMPLEMENTING_EDI 1
+#include "edi/edi.h"
+
+#define VALIDATE_PTR(_ptr,_err) do{if(!(_ptr))return _err; }while(0)
+#define GET_DATA(_ptr) (Object)
+
+#include "edi_io.inc.c"
+#include "edi_int.inc.c"
+
+// === STRUCTURES ===
+typedef struct sAcessEdiDriver {
+ struct sAcessEdiDriver *Next;
+ tDevFS_Driver Driver;
+ int FileCount;
+ struct {
+ char *Name;
+ tVFS_Node Node;
+ } *Files;
+ edi_object_metadata_t *Objects;
+ edi_initialization_t Init;
+ driver_finish_t Finish;
+} tAcessEdiDriver;
+
+// === PROTOTYPES ===
+ int EDI_Install(char **Arguments);
+ int EDI_DetectDriver(void *Base);
+ int EDI_LoadDriver(void *Base);
+vfs_node *EDI_FS_ReadDir(vfs_node *Node, int Pos);
+vfs_node *EDI_FS_FindDir(vfs_node *Node, char *Name);
+ int EDI_FS_CharRead(vfs_node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+ int EDI_FS_CharWrite(vfs_node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+ int EDI_FS_IOCtl(vfs_node *Node, int Id, void *Data);
+data_pointer EDI_GetInternalClass(edi_string_t ClassName);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, VERSION, EDI, EDI_Install, NULL, NULL);
+tModuleLoader gEDI_Loader = {
+ NULL, "EDI", EDI_DetectDriver, EDI_LoadDriver, NULL
+};
+tSpinlock glEDI_Drivers;
+tAcessEdiDriver *gEdi_Drivers = NULL;
+edi_class_declaration_t *gcEdi_IntClasses[] = {
+ &scEdi_Int_Class_IO, &scEdi_Int_Class_IRQ
+};
+#define NUM_INT_CLASSES (sizeof(gcEdi_IntClasses)/sizeof(gcEdi_IntClasses[0]))
+char *csCharNumbers[] = {"c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9"};
+char *csBlockNumbers[] = {"blk0", "blk1", "blk2", "blk3", "blk4", "blk5", "blk6", "blk7", "blk8", "blk9"};
+
+// === CODE ===
+/**
+ * \fn int EDI_Install(char **Arguments)
+ * \brief Stub intialisation routine
+ */
+int EDI_Install(char **Arguments)
+{
+ Module_RegisterLoader( &gEDI_Loader );
+ return 1;
+}
+
+/**
+ * \brief Detects if a driver should be loaded by the EDI subsystem
+ */
+int EDI_DetectDriver(void *Base)
+{
+ if( Binary_FindSymbol(BASE, "driver_init", NULL) == 0 )
+ return 0;
+
+ return 1;
+}
+
+/**
+ * \fn int Edi_LoadDriver(void *Base)
+ * \brief Load an EDI Driver from a loaded binary
+ * \param Base Binary Handle
+ * \return 0 on success, non zero on error
+ */
+int EDI_LoadDriver(void *Base)
+{
+ driver_init_t init;
+ driver_finish_t finish;
+ tAcessEdiDriver *info;
+ int i, j;
+ int devfsId;
+ edi_class_declaration_t *classes;
+
+ ENTER("pBase", Base);
+
+ // Get Functions
+ if( !Binary_FindSymbol(Base, "driver_init", (Uint*)&init)
+ || !Binary_FindSymbol(Base, "driver_finish", (Uint*)&finish) )
+ {
+ Warning("[EDI ] Driver %p does not provide both `driver_init` and `driver_finish`\n", Base);
+ Binary_Unload(Base);
+ return 0;
+ }
+
+ // Allocate Driver Information
+ info = malloc( sizeof(tAcessEdiDriver) );
+ info->Finish = finish;
+
+ // Initialise Driver
+ info->Init = init( 0, NULL ); // TODO: Implement Resources
+
+ LOG("info->Init.driver_name = '%s'", info->Init.driver_name);
+ LOG("info->Init.num_driver_classes = %i", info->Init.num_driver_classes);
+
+ // Count mappable classes
+ classes = info->Init.driver_classes;
+ info->FileCount = 0;
+ info->Objects = NULL;
+ for( i = 0, j = 0; i < info->Init.num_driver_classes; i++ )
+ {
+ if( strncmp(classes[i].name, "EDI-CHARACTER-DEVICE", 32) == 0 )
+ {
+ data_pointer *obj;
+ // Initialise Object Instances
+ for( ; (obj = classes[i].constructor()); j++ ) {
+ LOG("%i - Constructed '%s'", j, classes[i].name);
+ info->FileCount ++;
+ info->Objects = realloc(info->Objects, sizeof(*info->Objects)*info->FileCount);
+ info->Objects[j].object = obj;
+ info->Objects[j].object_class = &classes[i];
+ }
+ }
+ else
+ LOG("%i - %s", i, classes[i].name);
+ }
+
+ if(info->FileCount)
+ {
+ int iNumChar = 0;
+ // Create VFS Nodes
+ info->Files = malloc( info->FileCount * sizeof(*info->Files) );
+ memset(info->Files, 0, info->FileCount * sizeof(*info->Files));
+ j = 0;
+ for( j = 0; j < info->FileCount; j++ )
+ {
+ classes = info->Objects[j].object_class;
+ if( strncmp(classes->name, "EDI-CHARACTER-DEVICE", 32) == 0 )
+ {
+ LOG("%i - %s", j, csCharNumbers[iNumChar]);
+ info->Files[j].Name = csCharNumbers[iNumChar];
+ info->Files[j].Node.NumACLs = 1;
+ info->Files[j].Node.ACLs = &gVFS_ACL_EveryoneRW;
+ info->Files[j].Node.ImplPtr = &info->Objects[j];
+ info->Files[j].Node.Read = EDI_FS_CharRead;
+ info->Files[j].Node.Write = EDI_FS_CharWrite;
+ info->Files[j].Node.IOCtl = EDI_FS_IOCtl;
+ info->Files[j].Node.CTime =
+ info->Files[j].Node.MTime =
+ info->Files[j].Node.ATime = now();
+
+ iNumChar ++;
+ continue;
+ }
+ }
+
+ // Create DevFS Driver
+ info->Driver.ioctl = EDI_FS_IOCtl;
+ memsetda(&info->Driver.rootNode, 0, sizeof(vfs_node) / 4);
+ info->Driver.Name = info->Init.driver_name;
+ info->Driver.RootNode.Flags = VFS_FFLAG_DIRECTORY;
+ info->Driver.RootNode.NumACLs = 1;
+ info->Driver.RootNode.ACLs = &gVFS_ACL_EveryoneRX;
+ info->Driver.RootNode.Length = info->FileCount;
+ info->Driver.RootNode.ImplPtr = info;
+ info->Driver.RootNode.ReadDir = EDI_FS_ReadDir;
+ info->Driver.RootNode.FindDir = EDI_FS_FindDir;
+ info->Driver.RootNode.IOCtl = EDI_FS_IOCtl;
+
+ // Register
+ devfsId = dev_addDevice( &info->Driver );
+ if(devfsId == -1) {
+ free(info->Files); // Free Files
+ info->Finish(); // Clean up driver
+ free(info); // Free info structure
+ Binary_Unload(iDriverBase); // Unload library
+ return -3; // Return error
+ }
+ }
+
+ // Append to loaded list;
+ LOCK(&glEDI_Drivers);
+ info->Next = gEDI_Drivers;
+ gEDI_Drivers = info;
+ RELEASE(&glEDI_Drivers);
+
+ LogF("[EDI ] Loaded Driver '%s' (%s)\n", info->Init.driver_name, Path);
+ LEAVE('i', 1);
+ return 1;
+}
+
+// --- Filesystem Interaction ---
+/**
+ * \brief Read from a drivers class list
+ * \param Node Driver's Root Node
+ * \param Pos Index of file to get
+ */
+char *EDI_FS_ReadDir(tVFS_Node *Node, int Pos)
+{
+ tAcessEdiDriver *info;
+
+ // Sanity Check
+ if(!Node) return NULL;
+
+ // Get Information Structure
+ info = (void *) Node->ImplPtr;
+ if(!info) return NULL;
+
+ // Check Position
+ if(Pos < 0) return NULL;
+ if(Pos >= info->FileCount) return NULL;
+
+ return strdup( info->Files[Pos].Name );
+}
+
+/**
+ * \fn tVFS_Node *EDI_FS_FindDir(tVFS_Node *Node, char *Name)
+ * \brief Find a named file in a driver
+ * \param Node Driver's Root Node
+ * \param Name Name of file to find
+ */
+tVFS_Node *EDI_FS_FindDir(tVFS_Node *Node, char *Name)
+{
+ tAcessEdiDriver *info;
+ int i;
+
+ // Sanity Check
+ if(!Node) return NULL;
+ if(!Name) return NULL;
+
+ // Get Information Structure
+ info = (void *) Node->ImplPtr;
+ if(!info) return NULL;
+
+ for( i = 0; i < info->FileCount; i++ )
+ {
+ if(strcmp(info->Files[i].name, Name) == 0)
+ return &info->Files[i].Node;
+ }
+
+ return NULL;
+}
+
+/**
+ * \fn Uint64 EDI_FS_CharRead(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \brief Read from an EDI Character Device
+ * \param Node File Node
+ * \param Offset Offset into file (ignored)
+ * \param Length Number of characters to read
+ * \param Buffer Destination for data
+ * \return Number of characters read
+ */
+Uint64 EDI_FS_CharRead(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+ edi_object_metadata_t *meta;
+ edi_class_declaration_t *class;
+
+ // Sanity Check
+ if(!Node || !Buffer) return 0;
+ if(Length <= 0) return 0;
+ // Get Object Metadata
+ meta = (void *) Node->ImplPtr;
+ if(!meta) return 0;
+
+ // Get Class
+ class = meta->object_class;
+ if(!class) return 0;
+
+ // Read from object
+ if( ((tAnyFunction) class->methods[0].code)( meta->object, Buffer, Length ))
+ return Length;
+
+ return 0;
+}
+
+/**
+ * \fn Uint64 EDI_FS_CharWrite(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+ * \brief Write to an EDI Character Device
+ * \param Node File Node
+ * \param Offset Offset into file (ignored)
+ * \param Length Number of characters to write
+ * \param Buffer Source for data
+ * \return Number of characters written
+ */
+Uint64 EDI_FS_CharWrite(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
+{
+ edi_object_metadata_t *meta;
+ edi_class_declaration_t *class;
+
+ // Sanity Check
+ if(!Node || !Buffer) return 0;
+ if(Length <= 0) return 0;
+ // Get Object Metadata
+ meta = (void *) Node->ImplPtr;
+ if(!meta) return 0;
+
+ // Get Class
+ class = meta->object_class;
+ if(!class) return 0;
+
+ // Write to object
+ if( ((tAnyFunction) class->methods[1].code)( meta->object, Buffer, Length ))
+ return Length;
+
+ return 0;
+}
+
+/**
+ * \fn int EDI_FS_IOCtl(tVFS_Node *Node, int Id, void *Data)
+ * \brief Perfom an IOCtl call on the object
+ */
+int EDI_FS_IOCtl(tVFS_Node *Node, int Id, void *Data)
+{
+ return 0;
+}
+
+// --- EDI Functions ---
+/**
+ * \fn data_pointer EDI_GetDefinedClass(edi_string_t ClassName)
+ * \brief Gets the structure of a driver defined class
+ * \param ClassName Name of class to find
+ * \return Class definition or NULL
+ */
+data_pointer EDI_GetDefinedClass(edi_string_t ClassName)
+{
+ int i;
+ tAcessEdiDriver *drv;
+ edi_class_declaration_t *classes;
+
+ for(drv = gEdi_Drivers;
+ drv;
+ drv = drv->Next )
+ {
+ classes = drv->Init.driver_classes;
+ for( i = 0; i < drv->Init.num_driver_classes; i++ )
+ {
+ if( strncmp(classes[i].name, ClassName, 32) == 0 )
+ return &classes[i];
+ }
+ }
+ return NULL;
+}
+
+/**
+ * \fn int32_t EDI_CheckClassExistence(edi_string_t ClassName)
+ * \brief Checks if a class exists
+ * \param ClassName Name of class
+ * \return 1 if the class exists, -1 otherwise
+ */
+int32_t EDI_CheckClassExistence(edi_string_t ClassName)
+{
+ //LogF("check_class_existence: (ClassName='%s')\n", ClassName);
+ if(EDI_GetInternalClass(ClassName))
+ return 1;
+
+ if(EDI_GetDefinedClass(ClassName)) // Driver Defined
+ return 1;
+
+ return -1;
+}
+
+/**
+ * \fn edi_object_metadata_t EDI_ConstructObject(edi_string_t ClassName)
+ * \brief Construct an instance of an class (an object)
+ * \param ClassName Name of the class to construct
+ */
+edi_object_metadata_t EDI_ConstructObject(edi_string_t ClassName)
+{
+ edi_object_metadata_t ret = {0, 0};
+ edi_class_declaration_t *class;
+
+ //LogF("EDI_ConstructObject: (ClassName='%s')\n", ClassName);
+
+ // Get class definition
+ if( !(class = EDI_GetInternalClass(ClassName)) ) // Internal
+ if( !(class = EDI_GetDefinedClass(ClassName)) ) // Driver Defined
+ return ret; // Return ERROR
+
+ // Initialise
+ ret.object = class->constructor();
+ if( !ret.object )
+ return ret; // Return ERROR
+
+ // Set declaration pointer
+ ret.object_class = class;
+
+ //LogF("EDI_ConstructObject: RETURN {0x%x,0x%x}\n", ret.object, ret.object_class);
+ return ret;
+}
+
+/**
+ * \fn void EDI_DestroyObject(edi_object_metadata_t Object)
+ * \brief Destroy an instance of a class
+ * \param Object Object to destroy
+ */
+void EDI_DestroyObject(edi_object_metadata_t Object)
+{
+ if( !Object.object ) return;
+ if( !Object.object_class ) return;
+
+ ((edi_class_declaration_t*)(Object.object_class))->destructor( &Object );
+}
+
+/**
+ * \fn function_pointer EDI_GetMethodByName(data_pointer ObjectClass, edi_string_t MethodName)
+ * \brief Get a method of a class by it's name
+ * \param ObjectClass Pointer to a ::edi_object_metadata_t of the object
+ * \param MethodName Name of the desired method
+ * \return Function address or NULL
+ */
+function_pointer EDI_GetMethodByName(data_pointer ObjectClass, edi_string_t MethodName)
+{
+ edi_class_declaration_t *dec = ObjectClass;
+ int i;
+
+ //LogF("get_method_by_name: (ObjectClass=0x%x, MethodName='%s')\n", ObjectClass, MethodName);
+
+ if(!ObjectClass) return NULL;
+
+ for(i = 0; i < dec->num_methods; i++)
+ {
+ if(strncmp(MethodName, dec->methods[i].name, 32) == 0)
+ return dec->methods[i].code;
+ }
+ return NULL;
+}
+
+#if 0
+function_pointer get_method_by_declaration(data_pointer Class, edi_function_declaration_t Declaration);
+#endif
+
+/**
+ * \fn edi_string_ptr_t EDI_GetClassParent(edi_string_t ClassName)
+ * \brief Get the parent of the named class
+ * \todo Implement
+ */
+edi_string_ptr_t EDI_GetClassParent(edi_string_t ClassName)
+{
+ WarningEx("EDI", "`get_class_parent` is unimplemented");
+ return NULL;
+}
+
+/**
+ * \fn data_pointer EDI_GetInternalClass(edi_string_t ClassName)
+ * \brief Get a builtin class
+ * \param ClassName Name of class to find
+ * \return Pointer to the ::edi_class_declaration_t of the class
+ */
+data_pointer EDI_GetInternalClass(edi_string_t ClassName)
+{
+ int i;
+ //LogF("get_internal_class: (ClassName='%s')\n", ClassName);
+ for( i = 0; i < NUM_INT_CLASSES; i++ )
+ {
+ if( strncmp( gcEdi_IntClasses[i]->name, ClassName, 32 ) == 0 ) {
+ return gcEdi_IntClasses[i];
+ }
+ }
+ //LogF("get_internal_class: RETURN NULL\n");
+ return NULL;
+}
+
+/**
+ * \fn edi_string_ptr_t EDI_GetObjectClass(data_pointer Object)
+ * \brief Get the name of the object of \a Object
+ * \param Object Object to get name of
+ * \return Pointer to the class name
+ */
+edi_string_ptr_t EDI_GetObjectClass(data_pointer ObjectClass)
+{
+ edi_object_metadata_t *Metadata = ObjectClass;
+ // Sanity Check
+ if(!ObjectClass) return NULL;
+ if(!(edi_class_declaration_t*) Metadata->object_class) return NULL;
+
+ // Return Class Name
+ return ((edi_class_declaration_t*) Metadata->object_class)->name;
+}
+
+// === EXPORTS ===
+EXPORTAS(EDI_CheckClassExistence, check_class_existence);
+EXPORTAS(EDI_ConstructObject, construct_object);
+EXPORTAS(EDI_DestroyObject, destroy_object);
+EXPORTAS(EDI_GetMethodByName, get_method_by_name);
+EXPORTAS(EDI_GetClassParent, get_class_parent);
+EXPORTAS(EDI_GetInternalClass, get_internal_class);
+EXPORTAS(EDI_GetObjectClass, get_object_class);
/**
* \file cb.c
* \author John Hodge (thePowersGang)
+ * \brief Control block code
*/
#include <acess.h>
#include <udi.h>
-// === EXPORTS ===
-EXPORT(udi_cb_alloc);
-EXPORT(udi_cb_alloc_dynamic);
-EXPORT(udi_cb_alloc_batch);
-EXPORT(udi_cb_free);
-EXPORT(udi_cancel);
-
// === CODE ===
void udi_cb_alloc (
- udi_cb_alloc_call_t *callback,
- udi_cb_t *gcb,
- udi_index_t cb_idx,
- udi_channel_t default_channel
+ udi_cb_alloc_call_t *callback, //!< Function to be called when the CB is allocated
+ udi_cb_t *gcb, //!< Parent Control Block
+ udi_index_t cb_idx,
+ udi_channel_t default_channel
)
{
UNIMPLEMENTED();
}
void udi_cb_alloc_batch(
- udi_cb_alloc_batch_call_t *callback,
- udi_cb_t *gcb,
+ udi_cb_alloc_batch_call_t *callback, //!<
+ udi_cb_t *gcb, //!<
udi_index_t cb_idx,
udi_index_t count,
udi_boolean_t with_buf,
{
UNIMPLEMENTED();
}
+
+// === EXPORTS ===
+EXPORT(udi_cb_alloc);
+EXPORT(udi_cb_alloc_dynamic);
+EXPORT(udi_cb_alloc_batch);
+EXPORT(udi_cb_free);
+EXPORT(udi_cancel);
int UDI_Install(char **Arguments)
{
Module_RegisterLoader( &gUDI_Loader );
- return 1;
+ return MODULE_ERR_OK;
}
/**
// === CODE ===
udi_size_t udi_snprintf(char *s, udi_size_t max_bytes, const char *format, ...)
{
- s[0] = '\0';
- return 0;
+ udi_size_t ret;
+ va_list args;
+ va_start(args, format);
+
+ ret = vsnprintf(s, max_bytes, format, args);
+
+ va_end(args);
+ return ret;
}
-include $(CFGFILES)
CPPFLAGS = -I$(ACESSDIR)/Kernel/include -I$(ACESSDIR)/Kernel/arch/$(ARCHDIR)/include -DARCH=$(ARCH) $(_CPPFLAGS)
-CFLAGS = -Wall -Werror -fno-stack-protector $(CPPFLAGS)
+CFLAGS = -Wall -Werror -fno-stack-protector $(CPPFLAGS) -O3
OBJ := $(addsuffix .$(ARCH),$(OBJ))
-BIN = ../$(NAME).kmd.$(ARCH)
+ifneq ($(CATEGORY),)
+ BIN := ../$(CATEGORY)_$(NAME).kmd.$(ARCH)
+else
+ BIN := ../$(NAME).kmd.$(ARCH)
+endif
KOBJ = ../$(NAME).xo.$(ARCH)
DEPFILES = $(filter %.o.$(ARCH),$(OBJ))
+CATEGORY = Network
+
-include ../../Makefile.tpl
giNe2k_CardCount += PCI_CountDevices( csaCOMPAT_DEVICES[i].Vendor, csaCOMPAT_DEVICES[i].Device, 0 );
}
+ if( giNe2k_CardCount == 0 ) {
+ Log_Warning("Ne2k", "No cards detected");
+ return MODULE_ERR_NOTNEEDED;
+ }
+
// Enumerate Cards
k = 0;
gpNe2k_Cards = calloc( giNe2k_CardCount, sizeof(tCard) );
Ne2k_WriteReg(base, MAC5, gpNe2k_Cards[ k ].MacAddr[5]);
*/
- Log("[NE2K]: Card #%i: IRQ=%i, IOBase=0x%x",
- k, gpNe2k_Cards[ k ].IRQ, gpNe2k_Cards[ k ].IOBase);
- Log("MAC Address %x:%x:%x:%x:%x:%x",
- gpNe2k_Cards[ k ].MacAddr[0], gpNe2k_Cards[ k ].MacAddr[1],
- gpNe2k_Cards[ k ].MacAddr[2], gpNe2k_Cards[ k ].MacAddr[3],
- gpNe2k_Cards[ k ].MacAddr[4], gpNe2k_Cards[ k ].MacAddr[5]
+ Log_Log("Ne2k", "Card %i 0x%04x IRQ%i %02x:%02x:%02x:%02x:%02x:%02x",
+ k, base, gpNe2k_Cards[ k ].IRQ,
+ gpNe2k_Cards[k].MacAddr[0], gpNe2k_Cards[k].MacAddr[1],
+ gpNe2k_Cards[k].MacAddr[2], gpNe2k_Cards[k].MacAddr[3],
+ gpNe2k_Cards[k].MacAddr[4], gpNe2k_Cards[k].MacAddr[5]
);
// Set VFS Node
gNe2k_DriverInfo.RootNode.Size = giNe2k_CardCount;
DevFS_AddDevice( &gNe2k_DriverInfo );
- return 1;
+ return MODULE_ERR_OK;
}
/**
// Sanity Check Length
if(Length > TX_BUF_SIZE*256) {
- Warning(
+ Log_Warning(
+ "Ne2k",
"Ne2k_Write - Attempting to send over TX_BUF_SIZE*256 (%i) bytes (%i)",
TX_BUF_SIZE*256, Length
);
return ;
}
}
- Warning("[NE2K ] Recieved Unknown IRQ %i", IntNum);
+ Log_Warning("Ne2k", "Recieved Unknown IRQ %i", IntNum);
}
--- /dev/null
+/* Acess2 RTL8139 Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * main.c - Driver Core
+ */
+#define DEBUG 0
+#define VERSION ((0<<8)|50)
+#include <acess.h>
+#include <modules.h>
+#include <fs_devfs.h>
+#include <drv_pci.h>
+#include <tpl_drv_network.h>
+
+// === CONSTANTS ===
+enum eRTL8139_Regs
+{
+ MAC0, MAC1, MAC2,
+ MAC3, MAC4, MAC5,
+ MAR0 = 0x08,
+ MAR1, MAR2, MAR3,
+ MAR4, MAR5, MAR6, MAR7,
+
+ RBSTART = 0x30, //!< Recieve Buffer Start
+ // ??, ??, ??, RST, RE, TE, ??, ??
+ CMD = 0x37,
+ IMR = 0x3C,
+ ISR = 0x3E,
+
+ RCR = 0x44,
+
+ CONFIG1 = 0x52
+};
+
+// === TYPES ===
+typedef struct sCard
+{
+ Uint16 IOBase;
+ Uint8 IRQ;
+
+ int NumWaitingPackets;
+
+ void *ReceiveBuffer;
+ tPAddr PhysReceiveBuffer;
+
+ char Name[2];
+ tVFS_Node Node;
+ Uint8 MacAddr[6];
+} tCard;
+
+// === PROTOTYPES ===
+
+// === GLOBALS ===
+MODULE_DEFINE(0, VERSION, RTL8139, RTL8139_Install, NULL, NULL);
+ int giRTL8139_CardCount;
+tCard gpRTL8139_Cards;
+
+// === CODE ===
+/**
+ * \brief Installs the RTL8139 Driver
+ */
+int RTL8139_Install(char **Options)
+{
+ int id = -1;
+ int i = 0;
+ Uint16 base;
+
+ giRTL8139_CardCount = PCI_CountDevices( 0x10EC, 0x8139, 0 );
+
+ gpRTL8139_Cards = calloc( giRTL8139_CardCount, sizeof(tCard) );
+
+
+ while( (id = PCI_GetDevice(0x10EC, 0x8139, 0, id)) != -1 )
+ {
+ base = PCI_AssignPort( id, 0, 0x100 );
+ gpRTL8139_Cards[i].IOBase = base;
+ gpRTL8139_Cards[i].IRQ = PCI_GetIRQ( id );
+
+ // Install IRQ Handler
+ IRQ_AddHandler(gpRTL8139_Cards[ k ].IRQ, RTL8136_IRQHandler);
+
+ // Power on
+ outb( base + CONFIG1, 0x00 );
+ // Reset (0x10 to CMD)
+ outb( base + CMD, 0x10 );
+
+ gpRTL8139_Cards[i].ReceiveBuffer = MM_AllocDMA( 2, 32, &gpRTL8139_Cards[i].PhysReceiveBuffer );
+ // Set up recieve buffer
+ outl(base + RBSTART, (Uint32)gpRTL8139_Cards[i].PhysReceiveBuffer);
+ // Set IMR to Transmit OK and Receive OK
+ outw(base + IMR, 0x5);
+
+ // Set recieve buffer size, buffer wrap and recieve mask
+ outl(base + RCR, 0x8F);
+
+ outb(base + CMD, 0x0C); // Recive Enable and Transmit Enable
+
+ gpRTL8139_Cards[ i ].MacAddr[0] = inb(base+MAC0);
+ gpRTL8139_Cards[ i ].MacAddr[1] = inb(base+MAC1);
+ gpRTL8139_Cards[ i ].MacAddr[2] = inb(base+MAC2);
+ gpRTL8139_Cards[ i ].MacAddr[3] = inb(base+MAC3);
+ gpRTL8139_Cards[ i ].MacAddr[4] = inb(base+MAC4);
+ gpRTL8139_Cards[ i ].MacAddr[5] = inb(base+MAC5);
+
+ // Set VFS Node
+ gpRTL8139_Cards[ i ].Name[0] = '0'+i;
+ gpRTL8139_Cards[ i ].Name[1] = '\0';
+ gpRTL8139_Cards[ i ].Node.ImplPtr = &gpRTL8139_Cards[ i ];
+ gpRTL8139_Cards[ i ].Node.NumACLs = 0;
+ gpRTL8139_Cards[ i ].Node.CTime = now();
+ gpRTL8139_Cards[ i ].Node.Write = RTL8139_Write;
+ gpRTL8139_Cards[ i ].Node.Read = RTL8139_Read;
+ gpRTL8139_Cards[ i ].Node.IOCtl = RTL8139_IOCtl;
+
+ Log_Log("RTL8139", "Card %i 0x%04x %02x:%02x:%02x:%02x:%02x:%02x",
+ i, base,
+ gpRTL8139_Cards[ i ].MacAddr[0], gpRTL8139_Cards[ i ].MacAddr[1],
+ gpRTL8139_Cards[ i ].MacAddr[2], gpRTL8139_Cards[ i ].MacAddr[3],
+ gpRTL8139_Cards[ i ].MacAddr[4], gpRTL8139_Cards[ i ].MacAddr[5]
+ );
+
+ i ++;
+ }
+ return MODULE_ERR_OK;
+}
* Acess2 IDE Harddisk Driver
* - main.c
*/
-#define DEBUG 1
+#define DEBUG 0
#include <acess.h>
#include <modules.h>
#include <vfs.h>
void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value);
// === GLOBALS ===
-MODULE_DEFINE(0, 0x0032, i386ATA, ATA_Install, NULL, NULL);
+MODULE_DEFINE(0, 0x0032, i386ATA, ATA_Install, NULL, "PCI", NULL);
tDevFS_Driver gATA_DriverInfo = {
NULL, "ata",
{
int ret;
ret = ATA_SetupIO();
- if(ret != 1) return ret;
+ if(ret) return ret;
ATA_SetupPartitions();
ATA_SetupVFS();
if( DevFS_AddDevice( &gATA_DriverInfo ) == 0 )
- return MODULE_INIT_FAILURE;
+ return MODULE_ERR_MISC;
- return MODULE_INIT_SUCCESS;
+ return MODULE_ERR_OK;
}
/**
gATA_BusMasterBase = PCI_GetBAR4( ent );
if( gATA_BusMasterBase == 0 ) {
Warning("It seems that there is no Bus Master Controller on this machine. Get one");
- LEAVE('i', MODULE_INIT_FAILURE);
- return MODULE_INIT_FAILURE;
+ LEAVE('i', MODULE_ERR_NOTNEEDED);
+ return MODULE_ERR_NOTNEEDED;
}
+
+ // Map memory
if( !(gATA_BusMasterBase & 1) )
{
if( gATA_BusMasterBase < 0x100000 )
gATA_BusMasterBasePtr = (void*)(0xC0000000|gATA_BusMasterBase);
else
- gATA_BusMasterBasePtr = (void*)( MM_MapHWPage( gATA_BusMasterBase, 1 ) + (gATA_BusMasterBase&0xFFF) );
+ gATA_BusMasterBasePtr = (void*)( MM_MapHWPages( gATA_BusMasterBase, 1 ) + (gATA_BusMasterBase&0xFFF) );
LOG("gATA_BusMasterBasePtr = %p", gATA_BusMasterBasePtr);
}
else {
LOG("gATA_BusMasterBase = 0x%x", gATA_BusMasterBase & ~1);
}
+ // Register IRQs and get Buffers
IRQ_AddHandler( gATA_IRQPri, ATA_IRQHandlerPri );
IRQ_AddHandler( gATA_IRQSec, ATA_IRQHandlerSec );
LOG("addr = 0x%x", addr);
ATA_int_BusMasterWriteDWord(12, addr);
+ // Enable controllers
outb(IDE_PRI_BASE+1, 1);
outb(IDE_SEC_BASE+1, 1);
- LEAVE('i', MODULE_INIT_SUCCESS);
- return MODULE_INIT_SUCCESS;
+ // return
+ LEAVE('i', MODULE_ERR_OK);
+ return MODULE_ERR_OK;
}
/**
#define FDD_VERSION ((0<<8)|(75))\r
\r
// --- Options\r
-#define USE_CACHE 0 // Use Sector Cache\r
-#define CACHE_SIZE 32 // Number of cachable sectors\r
#define FDD_SEEK_TIMEOUT 10 // Timeout for a seek operation\r
#define MOTOR_ON_DELAY 500 // Miliseconds\r
#define MOTOR_OFF_DELAY 2000 // Miliseconds\r
+#define FDD_MAX_READWRITE_ATTEMPTS 16\r
\r
// === TYPEDEFS ===\r
/**\r
* \brief Representation of a floppy drive\r
*/\r
-typedef struct {\r
+typedef struct sFloppyDrive\r
+{\r
int type;\r
volatile int motorState; //2 - On, 1 - Spinup, 0 - Off\r
int track[2];\r
static const char *cFDD_TYPES[] = {"None", "360kB 5.25\"", "1.2MB 5.25\"", "720kB 3.5\"", "1.44MB 3.5\"", "2.88MB 3.5\"" };\r
static const int cFDD_SIZES[] = { 0, 360*1024, 1200*1024, 720*1024, 1440*1024, 2880*1024 };\r
static const short cPORTBASE[] = { 0x3F0, 0x370 };\r
+#if DEBUG\r
+static const char *cFDD_STATUSES[] = {NULL, "Error", "Invalid command", "Drive not ready"};\r
+#endif\r
\r
enum FloppyPorts {\r
PORT_STATUSA = 0x0,\r
// === PROTOTYPES ===\r
// --- Filesystem\r
int FDD_Install(char **Arguments);\r
+void FDD_UnloadModule();\r
+// --- VFS Methods\r
char *FDD_ReadDir(tVFS_Node *Node, int pos);\r
tVFS_Node *FDD_FindDir(tVFS_Node *dirNode, char *Name);\r
int FDD_IOCtl(tVFS_Node *Node, int ID, void *Data);\r
Uint64 FDD_ReadFS(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer);\r
-// --- 1st Level Disk Access\r
+// --- Functions for IOCache/DrvUtil\r
Uint FDD_ReadSectors(Uint64 SectorAddr, Uint Count, void *Buffer, Uint Disk);\r
// --- Raw Disk Access\r
int FDD_ReadSector(Uint32 disk, Uint64 lba, void *Buffer);\r
int FDD_WriteSector(Uint32 Disk, Uint64 LBA, void *Buffer);\r
// --- Helpers\r
void FDD_IRQHandler(int Num);\r
-void FDD_WaitIRQ();\r
+inline void FDD_WaitIRQ();\r
void FDD_SensInt(int base, Uint8 *sr0, Uint8 *cyl);\r
-inline void FDD_AquireSpinlock();\r
-inline void FDD_FreeSpinlock();\r
-#if USE_CACHE\r
-inline void FDD_AquireCacheSpinlock();\r
-inline void FDD_FreeCacheSpinlock();\r
-#endif\r
void FDD_int_SendByte(int base, char byte);\r
int FDD_int_GetByte(int base);\r
void FDD_Reset(int id);\r
int FDD_int_GetDims(int type, int lba, int *c, int *h, int *s, int *spt);\r
\r
// === GLOBALS ===\r
-MODULE_DEFINE(0, FDD_VERSION, FDD, FDD_Install, NULL, NULL);\r
+MODULE_DEFINE(0, FDD_VERSION, FDD, FDD_Install, NULL, "ISADMA", NULL);\r
t_floppyDevice gFDD_Devices[2];\r
-volatile int fdd_inUse = 0;\r
-volatile int fdd_irq6 = 0;\r
+tSpinlock glFDD;\r
+volatile int gbFDD_IrqFired = 0;\r
tDevFS_Driver gFDD_DriverInfo = {\r
NULL, "fdd",\r
{\r
.IOCtl = FDD_IOCtl\r
}\r
};\r
-#if USE_CACHE\r
-int siFDD_CacheInUse = 0;\r
-int siFDD_SectorCacheSize = CACHE_SIZE;\r
-t_floppySector sFDD_SectorCache[CACHE_SIZE];\r
-#endif\r
\r
// === CODE ===\r
/**\r
gFDD_Devices[0].track[0] = -1;\r
gFDD_Devices[1].track[1] = -1;\r
\r
- Log("[FDD ] Detected Disk 0: %s and Disk 1: %s", cFDD_TYPES[data>>4], cFDD_TYPES[data&0xF]);\r
+ Log_Log("FDD", "Detected Disk 0: %s and Disk 1: %s", cFDD_TYPES[data>>4], cFDD_TYPES[data&0xF]);\r
+ \r
+ if( data == 0 ) {\r
+ return MODULE_ERR_NOTNEEDED;\r
+ }\r
\r
// Clear FDD IRQ Flag\r
FDD_SensInt(0x3F0, NULL, NULL);\r
gFDD_Devices[0].Node.Flags = 0;\r
gFDD_Devices[0].Node.NumACLs = 0;\r
gFDD_Devices[0].Node.Read = FDD_ReadFS;\r
- gFDD_Devices[0].Node.Write = NULL;//fdd_writeFS;\r
+ gFDD_Devices[0].Node.Write = NULL;//FDD_WriteFS;\r
memcpy(&gFDD_Devices[1].Node, &gFDD_Devices[0].Node, sizeof(tVFS_Node));\r
\r
gFDD_Devices[1].Node.Inode = 1;\r
gFDD_Devices[1].Node.Size = cFDD_SIZES[data & 0xF];\r
\r
// Create Sector Cache\r
- #if USE_CACHE\r
- //sFDD_SectorCache = malloc(sizeof(*sFDD_SectorCache)*CACHE_SIZE);\r
- //siFDD_SectorCacheSize = CACHE_SIZE;\r
- #else\r
- if( cFDD_SIZES[data >> 4] ) {\r
+ if( cFDD_SIZES[data >> 4] )\r
+ {\r
gFDD_Devices[0].CacheHandle = IOCache_Create(\r
FDD_WriteSector, 0, 512,\r
gFDD_Devices[0].Node.Size / (512*4)\r
); // Cache is 1/4 the size of the disk\r
}\r
- if( cFDD_SIZES[data & 15] ) {\r
+ if( cFDD_SIZES[data & 15] )\r
+ {\r
gFDD_Devices[1].CacheHandle = IOCache_Create(\r
FDD_WriteSector, 0, 512,\r
gFDD_Devices[1].Node.Size / (512*4)\r
); // Cache is 1/4 the size of the disk\r
}\r
- #endif\r
\r
// Register with devfs\r
DevFS_AddDevice(&gFDD_DriverInfo);\r
\r
- return 1;\r
+ return MODULE_ERR_OK;\r
+}\r
+\r
+/**\r
+ * \brief Prepare the module for removal\r
+ */\r
+void FDD_UnloadModule()\r
+{\r
+ int i;\r
+ //DevFS_DelDevice( &gFDD_DriverInfo );\r
+ LOCK(&glFDD);\r
+ for(i=0;i<4;i++) {\r
+ Time_RemoveTimer(gFDD_Devices[i].timer);\r
+ FDD_int_StopMotor(i);\r
+ }\r
+ RELEASE(&glFDD);\r
+ //IRQ_Clear(6);\r
}\r
\r
/**\r
* \fn char *FDD_ReadDir(tVFS_Node *Node, int pos)\r
* \brief Read Directory\r
*/\r
-char *FDD_ReadDir(tVFS_Node *Node, int pos)\r
+char *FDD_ReadDir(tVFS_Node *Node, int Pos)\r
{\r
char name[2] = "0\0";\r
- //Update Accessed Time\r
- //gFDD_DrvInfo.rootNode.atime = now();\r
- \r
- //Check for bounds\r
- if(pos >= 2 || pos < 0)\r
- return NULL;\r
+\r
+ if(Pos >= 2 || Pos < 0) return NULL;\r
\r
- if(gFDD_Devices[pos].type == 0)\r
- return VFS_SKIP;\r
+ if(gFDD_Devices[Pos].type == 0) return VFS_SKIP;\r
\r
- name[0] += pos;\r
+ name[0] += Pos;\r
\r
- //Return\r
return strdup(name);\r
}\r
\r
*/\r
Uint64 FDD_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
{\r
- int i = 0;\r
- int disk;\r
- //Uint32 buf[128];\r
+ int ret;\r
\r
ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);\r
\r
return -1;\r
}\r
\r
- disk = Node->Inode;\r
- \r
- // Update Accessed Time\r
- Node->ATime = now();\r
- \r
- #if 0\r
- if((Offset & 0x1FF) || (Length & 0x1FF))\r
- {\r
- // Un-Aligned Offset/Length\r
- int startOff = Offset >> 9;\r
- int sectOff = Offset & 0x1FF;\r
- int sectors = (Length + 0x1FF) >> 9;\r
- \r
- LOG("Non-aligned Read");\r
- \r
- //Read Starting Sector\r
- if(!FDD_ReadSector(disk, startOff, buf))\r
- return 0;\r
- memcpy(Buffer, (char*)(buf+sectOff), Length > 512-sectOff ? 512-sectOff : Length);\r
- \r
- // If the data size is one sector or less\r
- if(Length <= 512-sectOff)\r
- {\r
- LEAVE('X', Length);\r
- return Length; //Return\r
- }\r
- Buffer += 512-sectOff;\r
- \r
- //Read Middle Sectors\r
- for( i = 1; i < sectors - 1; i++ )\r
- {\r
- if(!FDD_ReadSector(disk, startOff+i, buf)) {\r
- LEAVE('i', -1);\r
- return -1;\r
- }\r
- memcpy(Buffer, buf, 512);\r
- Buffer += 512;\r
- }\r
- \r
- //Read End Sectors\r
- if(!FDD_ReadSector(disk, startOff+i, buf))\r
- return 0;\r
- memcpy(Buffer, buf, (len&0x1FF)-sectOff);\r
-
- LEAVE('X', Length);\r
- return Length;\r
- }\r
- else\r
- {\r
- int count = Length >> 9;\r
- int sector = Offset >> 9;\r
- LOG("Aligned Read");\r
- //Aligned Offset and Length - Simple Code\r
- for( i = 0; i < count; i ++ )\r
- {\r
- FDD_ReadSector(disk, sector, buf);\r
- memcpy(buffer, buf, 512);\r
- buffer += 512;\r
- sector++;\r
- }
- LEAVE('i', Length);\r
- return Length;\r
- }\r
- #endif\r
- \r
- i = DrvUtil_ReadBlock(Offset, Length, Buffer, FDD_ReadSectors, 512, disk);\r
- LEAVE('i', i);\r
- return i;\r
+ ret = DrvUtil_ReadBlock(Offset, Length, Buffer, FDD_ReadSectors, 512, Node->Inode);\r
+ LEAVE('i', ret);\r
+ return ret;\r
}\r
\r
/**\r
- * \fn Uint FDD_ReadSectors(Uint64 SectorAddr, Uint Count, void *Buffer, Uint32 Disk)\r
* \brief Reads \a Count contiguous sectors from a disk\r
* \param SectorAddr Address of the first sector\r
* \param Count Number of sectors to read\r
return ret;\r
}\r
\r
-/**\r
- * \fn int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer)\r
- * \brief Read a sector from disk\r
- * \todo Make real-hardware safe (account for read errors)\r
-*/\r
-int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer)\r
+int FDD_int_ReadWriteSector(Uint32 Disk, Uint64 SectorAddr, int Write, void *Buffer)\r
{\r
int cyl, head, sec;\r
int spt, base;\r
int i;\r
int lba = SectorAddr;\r
+ Uint8 st0, st1, st2, rcy, rhe, rse, bps; // Status Values\r
\r
- ENTER("idisk Xlba pbuf", disk, lba, buf);\r
+ ENTER("iDisk XSectorAddr pBuffer", Disk, SectorAddr, Buffer);\r
\r
- #if USE_CACHE\r
- FDD_AquireCacheSpinlock();\r
- for( i = 0; i < siFDD_SectorCacheSize; i++ )\r
- {\r
- if(sFDD_SectorCache[i].timestamp == 0) continue;\r
- if(sFDD_SectorCache[i].disk == Disk\r
- && sFDD_SectorCache[i].sector == lba) {\r
- LOG("Found %i in cache %i", lba, i);\r
- memcpy(Buffer, sFDD_SectorCache[i].data, 512);\r
- sFDD_SectorCache[i].timestamp = now();\r
- FDD_FreeCacheSpinlock();\r
- LEAVE('i', 1);\r
- return 1;\r
- }\r
- }\r
- LOG("Read %i from Disk", lba);\r
- FDD_FreeCacheSpinlock();\r
- #else\r
- if( IOCache_Read( gFDD_Devices[Disk].CacheHandle, SectorAddr, Buffer ) == 1 ) {\r
- LEAVE('i', 1);\r
- return 1;\r
- }\r
- #endif\r
- \r
- base = cPORTBASE[Disk>>1];\r
+ base = cPORTBASE[Disk >> 1];\r
\r
LOG("Calculating Disk Dimensions");\r
// Get CHS position\r
- if(FDD_int_GetDims(gFDD_Devices[Disk].type, lba, &cyl, &head, &sec, &spt) != 1) {\r
+ if(FDD_int_GetDims(gFDD_Devices[Disk].type, lba, &cyl, &head, &sec, &spt) != 1)\r
+ {\r
LEAVE('i', -1);\r
return -1;\r
}\r
+ LOG("Cyl=%i, Head=%i, Sector=%i", cyl, head, sec);\r
\r
- // Remove Old Timer\r
- Time_RemoveTimer(gFDD_Devices[Disk].timer);\r
- // Check if Motor is on\r
- if(gFDD_Devices[Disk].motorState == 0) {\r
- FDD_int_StartMotor(Disk);\r
- }\r
+ LOCK(&glFDD); // Lock to stop the motor stopping on us\r
+ Time_RemoveTimer(gFDD_Devices[Disk].timer); // Remove Old Timer\r
+ // Start motor if needed\r
+ if(gFDD_Devices[Disk].motorState != 2) FDD_int_StartMotor(Disk);\r
+ RELEASE(&glFDD);\r
\r
- LOG("Wait for Motor Spinup");\r
+ LOG("Wait for the motor to spin up");\r
\r
// Wait for spinup\r
while(gFDD_Devices[Disk].motorState == 1) Threads_Yield();\r
\r
- LOG("C:%i,H:%i,S:%i", cyl, head, sec);\r
LOG("Acquire Spinlock");\r
- \r
- FDD_AquireSpinlock();\r
+ LOCK(&glFDD);\r
\r
// Seek to track\r
- outb(base+CALIBRATE_DRIVE, 0);\r
+ outb(base + CALIBRATE_DRIVE, 0);\r
i = 0;\r
- while(FDD_int_SeekTrack(Disk, head, (Uint8)cyl) == 0 && i++ < FDD_SEEK_TIMEOUT ) Threads_Yield();\r
+ while(FDD_int_SeekTrack(Disk, head, (Uint8)cyl) == 0 && i++ < FDD_SEEK_TIMEOUT )\r
+ Threads_Yield();\r
+ if( i > FDD_SEEK_TIMEOUT ) {\r
+ RELEASE(&glFDD);\r
+ LEAVE('i', 0);\r
+ return 0;\r
+ }\r
//FDD_SensInt(base, NULL, NULL); // Wait for IRQ\r
- \r
+ \r
+ // Read Data from DMA\r
LOG("Setting DMA for read");\r
+ DMA_SetChannel(2, 512, !Write); // Read 512 Bytes from channel 2\r
\r
- //Read Data from DMA\r
- DMA_SetChannel(2, 512, 1); // Read 512 Bytes\r
- \r
- LOG("Sending read command");\r
+ LOG("Sending command");\r
\r
//Threads_Wait(100); // Wait for Head to settle\r
Time_Delay(100);\r
- FDD_int_SendByte(base, READ_SECTOR); // Was 0xE6\r
- FDD_int_SendByte(base, (head << 2) | (Disk&1));\r
- FDD_int_SendByte(base, (Uint8)cyl);\r
- FDD_int_SendByte(base, (Uint8)head);\r
- FDD_int_SendByte(base, (Uint8)sec);\r
- FDD_int_SendByte(base, 0x02); // Bytes Per Sector (Real BPS=128*2^{val})\r
- FDD_int_SendByte(base, spt); // SPT\r
- FDD_int_SendByte(base, 0x1B); // Gap Length (27 is default)\r
- FDD_int_SendByte(base, 0xFF); // Data Length\r
\r
- // Wait for IRQ\r
- LOG("Waiting for Data to be read");\r
- FDD_WaitIRQ();\r
+ for( i = 0; i < FDD_MAX_READWRITE_ATTEMPTS; i ++ )\r
+ {\r
+ if( Write )\r
+ FDD_int_SendByte(base, READ_SECTOR); // Was 0xE6\r
+ else\r
+ FDD_int_SendByte(base, READ_SECTOR); // Was 0xE6\r
+ FDD_int_SendByte(base, (head << 2) | (Disk&1));\r
+ FDD_int_SendByte(base, (Uint8)cyl);\r
+ FDD_int_SendByte(base, (Uint8)head);\r
+ FDD_int_SendByte(base, (Uint8)sec);\r
+ FDD_int_SendByte(base, 0x02); // Bytes Per Sector (Real BPS=128*2^{val})\r
+ FDD_int_SendByte(base, spt); // SPT\r
+ FDD_int_SendByte(base, 0x1B); // Gap Length (27 is default)\r
+ FDD_int_SendByte(base, 0xFF); // Data Length\r
+ \r
+ // Wait for IRQ\r
+ if( Write ) {\r
+ LOG("Writing Data");\r
+ DMA_WriteData(2, 512, Buffer);\r
+ LOG("Waiting for Data to be written");\r
+ FDD_WaitIRQ();\r
+ }\r
+ else {\r
+ LOG("Waiting for data to be read");\r
+ FDD_WaitIRQ();\r
+ LOG("Reading Data");\r
+ DMA_ReadData(2, 512, Buffer);\r
+ }\r
+ \r
+ // Clear Input Buffer\r
+ LOG("Clearing Input Buffer");\r
+ // Status Values\r
+ st0 = FDD_int_GetByte(base);\r
+ st1 = FDD_int_GetByte(base);\r
+ st2 = FDD_int_GetByte(base);\r
+ \r
+ // Cylinder, Head and Sector (mutilated in some way\r
+ rcy = FDD_int_GetByte(base);\r
+ rhe = FDD_int_GetByte(base);\r
+ rse = FDD_int_GetByte(base);\r
+ // Should be the BPS set above (0x02)\r
+ bps = FDD_int_GetByte(base);\r
+ \r
+ // Check Status\r
+ // - Error Code\r
+ if(st0 & 0xC0) {\r
+ LOG("Error (st0 & 0xC0) \"%s\"", cFDD_STATUSES[st0 >> 6]);\r
+ continue;\r
+ }\r
+ // - Status Flags\r
+ if(st0 & 0x08) { LOG("Drive not ready"); continue; }\r
+ if(st1 & 0x80) { LOG("End of Cylinder"); continue; }\r
+ if(st1 & 0x20) { LOG("CRC Error"); continue; }\r
+ if(st1 & 0x10) { LOG("Controller Timeout"); continue; }\r
+ if(st1 & 0x04) { LOG("No Data Found"); continue; }\r
+ if(st1 & 0x01 || st2 & 0x01) {\r
+ LOG("No Address mark found");\r
+ continue;\r
+ }\r
+ if(st2 & 0x40) { LOG("Deleted address mark"); continue; }\r
+ if(st2 & 0x20) { LOG("CRC error in data"); continue; }\r
+ if(st2 & 0x10) { LOG("Wrong Cylinder"); continue; }\r
+ if(st2 & 0x04) { LOG("uPD765 sector not found"); continue; }\r
+ if(st2 & 0x02) { LOG("Bad Cylinder"); continue; }\r
+ \r
+ if(bps != 0x2) {\r
+ LOG("Returned BPS = 0x%02x, not 0x02", bps);\r
+ continue;\r
+ }\r
+ \r
+ if(st1 & 0x02) {\r
+ LOG("Floppy not writable");\r
+ i = FDD_MAX_READWRITE_ATTEMPTS+1;\r
+ break;\r
+ }\r
+ \r
+ // Success!\r
+ break;\r
+ }\r
\r
- // Read Data from DMA\r
- LOG(" FDD_ReadSector: Reading Data");\r
- DMA_ReadData(2, 512, Buffer);\r
+ // Release Spinlock\r
+ LOG("Realeasing Spinlock and setting motor to stop");\r
+ RELEASE(&glFDD);\r
+ \r
+ if(i == FDD_MAX_READWRITE_ATTEMPTS) {\r
+ Log_Warning("FDD", "Exceeded %i attempts in %s the disk",\r
+ FDD_MAX_READWRITE_ATTEMPTS,\r
+ (Write ? "writing to" : "reading from")\r
+ );\r
+ }\r
\r
- // Clear Input Buffer\r
- LOG("Clearing Input Buffer");\r
- FDD_int_GetByte(base); FDD_int_GetByte(base); FDD_int_GetByte(base);\r
- FDD_int_GetByte(base); FDD_int_GetByte(base); FDD_int_GetByte(base); FDD_int_GetByte(base);\r
+ // Don't turn the motor off now, wait for a while\r
+ gFDD_Devices[Disk].timer = Time_CreateTimer(MOTOR_OFF_DELAY, FDD_int_StopMotor, (void*)Disk);\r
+\r
+ if( i < FDD_MAX_READWRITE_ATTEMPTS ) {\r
+ LEAVE('i', 0);\r
+ return 0;\r
+ }\r
+ else {\r
+ LEAVE('i', 1);\r
+ return 1;\r
+ }\r
+}\r
+\r
+/**\r
+ * \fn int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer)\r
+ * \brief Read a sector from disk\r
+ * \todo Make real-hardware safe (account for read errors)\r
+*/\r
+int FDD_ReadSector(Uint32 Disk, Uint64 SectorAddr, void *Buffer)\r
+{\r
+ int ret;\r
\r
- LOG("Realeasing Spinlock and Setting motor to stop");\r
- // Release Spinlock\r
- FDD_FreeSpinlock();\r
+ ENTER("iDisk XSectorAddr pBuffer", Disk, SectorAddr, Buffer);\r
\r
- //Set timer to turn off motor affter a gap\r
- gFDD_Devices[Disk].timer = Time_CreateTimer(MOTOR_OFF_DELAY, FDD_int_StopMotor, (void*)Disk); //One Shot Timer
+ if( IOCache_Read( gFDD_Devices[Disk].CacheHandle, SectorAddr, Buffer ) == 1 ) {\r
+ LEAVE('i', 1);\r
+ return 1;\r
+ }\r
+ \r
+ // Pass to general function\r
+ ret = FDD_int_ReadWriteSector(Disk, SectorAddr, 0, Buffer);
\r
- #if USE_CACHE\r
- {\r
- FDD_AquireCacheSpinlock();\r
- int oldest = 0;\r
- for(i=0;i<siFDD_SectorCacheSize;i++)\r
- {\r
- if(sFDD_SectorCache[i].timestamp == 0) {\r
- oldest = i;\r
- break;\r
- }\r
- if(sFDD_SectorCache[i].timestamp < sFDD_SectorCache[oldest].timestamp)\r
- oldest = i;\r
- }\r
- sFDD_SectorCache[oldest].timestamp = now();\r
- sFDD_SectorCache[oldest].disk = Disk;\r
- sFDD_SectorCache[oldest].sector = lba;\r
- memcpy(sFDD_SectorCache[oldest].data, Buffer, 512);\r
- FDD_FreeCacheSpinlock();\r
+ if( ret == 0 ) {\r
+ IOCache_Add( gFDD_Devices[Disk].CacheHandle, SectorAddr, Buffer );
+ LEAVE('i', 1);\r
+ return 1;\r
+ }\r
+ else {\r
+ LOG("Reading failed");\r
+ LEAVE('i', 0);\r
+ return 0;\r
}\r
- #else\r
- IOCache_Add( gFDD_Devices[Disk].CacheHandle, SectorAddr, Buffer );\r
- #endif\r
-
- LEAVE('i', 1);\r
- return 1;\r
}\r
\r
/**\r
*/\r
void FDD_IRQHandler(int Num)\r
{\r
- fdd_irq6 = 1;\r
+ gbFDD_IrqFired = 1;\r
}\r
\r
/**\r
* \fn FDD_WaitIRQ()\r
* \brief Wait for an IRQ6\r
*/\r
-void FDD_WaitIRQ()\r
+inline void FDD_WaitIRQ()\r
{\r
// Wait for IRQ\r
- while(!fdd_irq6) Threads_Yield();\r
- fdd_irq6 = 0;\r
+ while(!gbFDD_IrqFired) Threads_Yield();\r
+ gbFDD_IrqFired = 0;\r
}\r
\r
void FDD_SensInt(int base, Uint8 *sr0, Uint8 *cyl)\r
else FDD_int_GetByte(base);\r
}\r
\r
-void FDD_AquireSpinlock()\r
-{\r
- while(fdd_inUse)\r
- Threads_Yield();\r
- fdd_inUse = 1;\r
-}\r
-\r
-inline void FDD_FreeSpinlock()\r
-{\r
- fdd_inUse = 0;\r
-}\r
-\r
-#if USE_CACHE\r
-inline void FDD_AquireCacheSpinlock()\r
-{\r
- while(siFDD_CacheInUse) Threads_Yield();\r
- siFDD_CacheInUse = 1;\r
-}\r
-inline void FDD_FreeCacheSpinlock()\r
-{\r
- siFDD_CacheInUse = 0;\r
-}\r
-#endif\r
-\r
/**\r
* void FDD_int_SendByte(int base, char byte)\r
* \brief Sends a command to the controller\r
}\r
inb(0x80); //Delay\r
}\r
+ \r
#if WARN\r
- Warning("FDD_int_SendByte - Timeout sending byte 0x%x to base 0x%x\n", byte, base);\r
+ Warning("FDD_int_SendByte - Timeout sending byte 0x%x to base 0x%x\n", byte, base);\r
#endif\r
}\r
\r
void FDD_int_StopMotor(int disk)\r
{\r
Uint8 state;\r
+ if( IS_LOCKED(&glFDD) ) return ;\r
+ ENTER("iDisk", disk);\r
+ \r
state = inb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT );\r
state &= ~( 1 << (4+disk) );\r
outb( cPORTBASE[ disk>>1 ] + PORT_DIGOUTPUT, state );\r
gFDD_Devices[disk].motorState = 0;\r
-}\r
-\r
-/**\r
- * \fn void ModuleUnload()\r
- * \brief Prepare the module for removal\r
- */\r
-void ModuleUnload()\r
-{\r
- int i;\r
- FDD_AquireSpinlock();\r
- for(i=0;i<4;i++) {\r
- Time_RemoveTimer(gFDD_Devices[i].timer);\r
- FDD_int_StopMotor(i);\r
- }\r
- //IRQ_Clear(6);\r
+ LEAVE('-');\r
}\r
+CATEGORY = Storage
+
-include ../../Makefile.tpl
--- /dev/null
+#
+#
+
+OBJ = main.o uhci.o
+NAME = Core
+
+-include ../Makefile.tpl
--- /dev/null
+/*
+ * Acess2
+ * USB Stack
+ */
+#define VERSION ( (0<<8)| 5 )
+#define DEBUG 1
+#include <acess.h>
+#include <vfs.h>
+#include <fs_devfs.h>
+#include <modules.h>
+#include "usb.h"
+
+// === IMPORTS ===
+ int UHCI_Initialise();
+
+// === PROTOTYPES ===
+ int USB_Install(char **Arguments);
+void USB_Cleanup();
+char *USB_ReadDir(tVFS_Node *Node, int Pos);
+tVFS_Node *USB_FindDir(tVFS_Node *Node, char *Name);
+ int USB_IOCtl(tVFS_Node *Node, int Id, void *Data);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, VERSION, USB, USB_Install, NULL, NULL);
+tDevFS_Driver gUSB_DrvInfo = {
+ NULL, "usb", {
+ .NumACLs = 1,
+ .ACLs = &gVFS_ACL_EveryoneRX,
+ .Flags = VFS_FFLAG_DIRECTORY,
+ .ReadDir = USB_ReadDir,
+ .FindDir = USB_FindDir,
+ .IOCtl = USB_IOCtl
+ }
+};
+tUSBDevice *gUSB_Devices = NULL;
+tUSBHost *gUSB_Hosts = NULL;
+
+// === CODE ===
+/**
+ * \fn int ModuleLoad()
+ * \brief Called once module is loaded
+ */
+int USB_Install(char **Arguments)
+{
+ UHCI_Initialise();
+ Warning("[USB ] Not Complete - Devel Only");
+ return MODULE_ERR_OK;
+}
+
+/**
+ * \fn void USB_Cleanup()
+ * \brief Called just before module is unloaded
+ */
+void USB_Cleanup()
+{
+}
+
+/**
+ * \fn char *USB_ReadDir(tVFS_Node *Node, int Pos)
+ * \brief Read from the USB root
+ */
+char *USB_ReadDir(tVFS_Node *Node, int Pos)
+{
+ return NULL;
+}
+
+/**
+ * \fn tVFS_Node *USB_FindDir(tVFS_Node *Node, char *Name)
+ * \brief Locate an entry in the USB root
+ */
+tVFS_Node *USB_FindDir(tVFS_Node *Node, char *Name)
+{
+ return NULL;
+}
+
+/**
+ * \brief Handles IOCtl Calls to the USB driver
+ */
+int USB_IOCtl(tVFS_Node *Node, int Id, void *Data)
+{
+ return 0;
+}
--- /dev/null
+/*\r
+ * Acess 2 USB Stack\r
+ * Universal Host Controller Interface\r
+ */\r
+#define DEBUG 1\r
+#include <acess.h>\r
+#include <vfs.h>\r
+#include <drv_pci.h>\r
+#include "usb.h"\r
+#include "uhci.h"\r
+\r
+// === CONSTANTS ===\r
+#define MAX_CONTROLLERS 4\r
+#define NUM_TDs 1024\r
+\r
+// === PROTOTYPES ===\r
+ int UHCI_Initialise();\r
+void UHCI_Cleanup();\r
+ int UHCI_IOCtl(tVFS_Node *node, int id, void *data);\r
+ int UHCI_Int_InitHost(tUHCI_Controller *Host);\r
+\r
+// === GLOBALS ===
+//Uint gaFrameList[1024];\r
+tUHCI_TD gaUHCI_TDPool[NUM_TDs];\r
+tUHCI_Controller gUHCI_Controllers[MAX_CONTROLLERS];\r
+\r
+// === CODE ===\r
+/**\r
+ * \fn int UHCI_Initialise()\r
+ * \brief Called to initialise the UHCI Driver\r
+ */\r
+int UHCI_Initialise()\r
+{\r
+ int i=0, id=-1;\r
+ int ret;\r
+ Uint16 base;\r
+ \r
+ ENTER("");\r
+ \r
+ // Enumerate PCI Bus, getting a maximum of `MAX_CONTROLLERS` devices\r
+ while( (id = PCI_GetDeviceByClass(0x0C03, 0xFFFF, id)) >= 0 && i < MAX_CONTROLLERS )\r
+ {\r
+ gUHCI_Controllers[i].PciId = id;\r
+ // Assign a port range (BAR4, Reserve 32 ports)\r
+ base = PCI_AssignPort( id, 4, 0x20 );\r
+ gUHCI_Controllers[i].IOBase = base;\r
+ \r
+ Log("[USB ] Controller PCI #%i: IO Base = 0x%x", id, base);\r
+ \r
+ // Initialise Host\r
+ ret = UHCI_Int_InitHost(&gUHCI_Controllers[i]);\r
+ // Detect an error\r
+ if(ret != 0) {\r
+ LEAVE('i', ret);\r
+ return ret;\r
+ }\r
+ \r
+ i ++;\r
+ }\r
+ if(i == MAX_CONTROLLERS) {\r
+ Warning("[UHCI ] Over "EXPAND_STR(MAX_CONTROLLERS)" UHCI controllers detected, ignoring rest");\r
+ }\r
+ LEAVE('i', i);\r
+ return i;\r
+}\r
+\r
+/**\r
+ * \fn void UHCI_Cleanup()\r
+ * \brief Called just before module is unloaded\r
+ */\r
+void UHCI_Cleanup()\r
+{\r
+}
+\r
+/**\r
+ * \brief Sends a packet to a device endpoint\r
+ */\r
+int UHCI_SendPacket(int ControllerId, int Length)\r
+{\r
+ //tUHCI_TD *td = UHCI_AllocateTD();\r
+ return 0;\r
+}\r
+\r
+// === INTERNAL FUNCTIONS ===\r
+/**\r
+ * \fn int UHCI_Int_InitHost(tUCHI_Controller *Host)\r
+ * \brief Initialises a UHCI host controller\r
+ * \param Host Pointer - Host to initialise\r
+ */\r
+int UHCI_Int_InitHost(tUHCI_Controller *Host)\r
+{\r
+ ENTER("pHost", Host);\r
+ \r
+ // Allocate Frame List\r
+ Host->FrameList = (void *) MM_AllocDMA(1, 32, &Host->PhysFrameList); // 1 Page, 32-bit\r
+ if( !Host->FrameList ) {\r
+ Warning("[UHCI ] Unable to allocate frame list, aborting");\r
+ LEAVE('i', -1);\r
+ return -1;\r
+ }\r
+ LOG("Allocated frame list 0x%x (0x%x)", Host->FrameList, Host->PhysFrameList);\r
+ memsetd( Host->FrameList, 1, 1024 ); // Clear List (Disabling all entries)\r
+ \r
+ //! \todo Properly fill frame list\r
+ \r
+ // Set frame length to 1 ms\r
+ outb( Host->IOBase + SOFMOD, 64 );\r
+ \r
+ // Set Frame List Address\r
+ outd( Host->IOBase + FLBASEADD, Host->PhysFrameList );\r
+ \r
+ // Set Frame Number\r
+ outw( Host->IOBase + FRNUM, 0 );\r
+ \r
+ // Enable Interrupts\r
+ //PCI_WriteWord( Host->PciId, 0xC0, 0x2000 );\r
+ \r
+ LEAVE('i', 0);\r
+ return 0;\r
+}\r
--- /dev/null
+/*
+ * AcessOS Version 1
+ * USB Stack
+ * - Universal Host Controller Interface
+ */
+#ifndef _UHCI_H_
+#define _UHCI_H_
+
+// === TYPES ===
+typedef struct sUHCI_Controller tUHCI_Controller;
+typedef struct sUHCI_TD tUHCI_TD;
+typedef struct sUHCI_QH tUHCI_QH;
+
+// === STRUCTURES ===
+struct sUHCI_Controller
+{
+ /**
+ * \brief PCI Device ID
+ */
+ Uint16 PciId;
+
+ /**
+ * \brief IO Base Address
+ */
+ Uint16 IOBase;
+
+ /**
+ * \brief Frame list
+ *
+ * 31:4 - Frame Pointer
+ * 3:2 - Reserved
+ * 1 - QH/TD Selector
+ * 0 - Terminate (Empty Pointer)
+ */
+ Uint32 *FrameList;
+
+ /**
+ * \brief Physical Address of the Frame List
+ */
+ tPAddr PhysFrameList;
+};
+
+struct sUHCI_TD
+{
+ /**
+ * \brief Next Entry in list
+ *
+ * 31:4 - Address
+ * 3 - Reserved
+ * 2 - Depth/Breadth Select
+ * 1 - QH/TD Select
+ * 0 - Terminate (Last in List)
+ */
+ Uint32 Link;
+
+ /**
+ * \brief Control and Status Field
+ *
+ * 31:30 - Reserved
+ * 29 - Short Packet Detect (Input Only)
+ * 28:27 - Number of Errors Allowed
+ * 26 - Low Speed Device (Communicating with a low speed device)
+ * 25 - Isynchonious Select
+ * 24 - Interrupt on Completion (IOC)
+ * 23:16 - Status
+ * 23 - Active
+ * 22 - Stalled
+ * 21 - Data Buffer Error
+ * 20 - Babble Detected
+ * 19 - NAK Detected
+ * 18 - CRC/Timout Error
+ * 17 - Bitstuff Error
+ * 16 - Reserved
+ * 15:11 - Reserved
+ * 10:0 - Actual Length (Number of bytes transfered)
+ */
+ Uint32 Control;
+
+ /**
+ * \brief Packet Header
+ *
+ * 31:21 - Maximum Length (0=1, Max 0x4FF, 0x7FF=0)
+ * 20 - Reserved
+ * 19 - Data Toggle
+ * 18:15 - Endpoint
+ * 14:8 - Device Address
+ * 7:0 - PID (Packet Identifcation) - Only 96, E1, 2D allowed
+ */
+ Uint32 Token;
+
+ /**
+ * \brief Pointer to the data to send
+ */
+ Uint32 BufferPointer;
+};
+
+struct sUHCI_QH
+{
+ /**
+ * \brief Next Entry in list
+ *
+ * 31:4 - Address
+ * 3:2 - Reserved
+ * 1 - QH/TD Select
+ * 0 - Terminate (Last in List)
+ */
+ Uint32 Next;
+
+
+ /**
+ * \brief Next Entry in list
+ *
+ * 31:4 - Address
+ * 3:2 - Reserved
+ * 1 - QH/TD Select
+ * 0 - Terminate (Last in List)
+ */
+ Uint32 Child;
+};
+
+// === ENUMERATIONS ===
+enum eUHCI_IOPorts {
+ /**
+ * \brief USB Command Register
+ *
+ * 15:8 - Reserved
+ * 7 - Maximum Packet Size selector (1: 64 bytes, 0: 32 bytes)
+ * 6 - Configure Flag (No Hardware Effect)
+ * 5 - Software Debug (Don't think it will be needed)
+ * 4 - Force Global Resume
+ * 3 - Enter Global Suspend Mode
+ * 2 - Global Reset (Resets all devices on the bus)
+ * 1 - Host Controller Reset (Reset just the controller)
+ * 0 - Run/Stop
+ */
+ USBCMD = 0x00,
+ /**
+ * \brief USB Status Register
+ *
+ * 15:6 - Reserved
+ * 5 - HC Halted, set to 1 when USBCMD:RS is set to 0
+ * 4 - Host Controller Process Error (Errors related to the bus)
+ * 3 - Host System Error (Errors related to the OS/PCI Bus)
+ * 2 - Resume Detect (Set if a RESUME command is sent to the Controller)
+ * 1 - USB Error Interrupt
+ * 0 - USB Interrupts (Set if a transaction with the IOC bit set is completed)
+ */
+ USBSTS = 0x02,
+ /**
+ * \brief USB Interrupt Enable Register
+ *
+ * 15:4 - Reserved
+ * 3 - Short Packet Interrupt Enable
+ * 2 - Interrupt on Complete (IOC) Enable
+ * 1 - Resume Interrupt Enable
+ * 0 - Timout / CRC Error Interrupt Enable
+ */
+ USBINTR = 0x04,
+ /**
+ * \brief Frame Number (Index into the Frame List)
+ *
+ * 15:11 - Reserved
+ * 10:0 - Index (Incremented each approx 1ms)
+ */
+ FRNUM = 0x06,
+ /**
+ * \brief Frame List Base Address
+ *
+ * 31:12 - Pysical Address >> 12
+ * 11:0 - Reserved (Set to Zero)
+ */
+ FLBASEADD = 0x08, // 32-bit
+ /**
+ * \brief Start-of-frame Modify Register
+ * \note 8-bits only
+ *
+ * Sets the size of a frame
+ * Frequency = (11936+n)/12000 kHz
+ *
+ * 7 - Reserved
+ * 6:0 -
+ */
+ SOFMOD = 0x0C, // 8bit
+ /**
+ * \brief Port Status and Controll Register (Port 1)
+ *
+ * 15:13 - Reserved
+ * 12 - Suspend
+ * 11:10 - Reserved
+ * 9 - Port Reset
+ * 8 - Low Speed Device Attached
+ * 5:4 - Line Status
+ * 3 - Port Enable/Disable Change - Used for detecting device removal
+ * 2 - Port Enable/Disable
+ * 1 - Connect Status Change
+ * 0 - Current Connect Status
+ */
+ PORTSC1 = 0x10,
+ /**
+ * \brief Port Status and Controll Register (Port 2)
+ *
+ * See ::PORTSC1
+ */
+ PORTSC2 = 0x12
+};
+
+#endif
--- /dev/null
+/*
+ * Acess 2 USB Stack
+ * USB Packet Control
+ */
+#define DEBUG 1
+#include <acess.h>
+#include <vfs.h>
+#include <drv_pci.h>
+#include "usb.h"
+
+
+// === CODE ===
+void USB_MakeToken(void *Buf, int PID, int Addr, int EndP)
+{
+ Uint8 *tok = Buf;
+ int crc = 0;
+
+ tok[0] = PID & 0xFF;
+ tok[1] = (Addr & 0x7F) | ((EndP&1)<<7);
+ tok[2] = ((EndP >> 1) & 0x7) | crc;
+}
+
+#if 0
+void USB_SendData(int Controller, int Dev, int Endpoint, void *Data, int Length)
+{
+ Uint8 buf[Length+3+2/*?*/];
+
+ USB_MakeToken(buf, PID_DATA0, Dev, Endpoint);
+
+ switch(Controller & 0xF00)
+ {
+ case 1: // UHCI
+ UHCI_SendPacket(Controller & 0xFF);
+ break;
+ }
+}
+#endif
--- /dev/null
+/*
+ * AcessOS Version 1
+ * USB Stack
+ */
+#ifndef _USB_H_
+#define _USB_H_
+
+// === TYPES ===
+typedef struct sUSBHost tUSBHost;
+typedef struct sUSBDevice tUSBDevice;
+
+// === CONSTANTS ===
+enum eUSB_PIDs
+{
+ /**
+ * \name Token
+ * \{
+ */
+ PID_OUT = 0xE1,
+ PID_IN = 0x69,
+ PID_SOF = 0xA5,
+ PID_SETUP = 0x2D,
+ /**
+ * \}
+ */
+
+ /**
+ * \name Data
+ * \{
+ */
+ PID_DATA0 = 0xC3,
+ PID_DATA1 = 0x4B,
+ PID_DATA2 = 0x87, // USB2 only
+ PID_MDATA = 0x0F, // USB2 only
+ /**
+ * \}
+ */
+
+ /**
+ * \name Handshake
+ * \{
+ */
+ PID_ACK = 0xD2,
+ PID_NAK = 0x5A,
+ PID_STALL = 0x1E,
+ PID_NYET = 0x96,
+ /**
+ * \}
+ */
+
+ /**
+ * \name Special
+ * \{
+ */
+ PID_PRE = 0x3C, PID_ERR = 0x3C,
+ PID_SPLIT = 0x78,
+ PID_PING = 0xB4,
+ PID_RESVD = 0xF0,
+ /**
+ * \}
+ */
+};
+
+// === FUNCTIONS ===
+/**
+ * \note 00101 - X^5+X^2+1
+ */
+Uint8 USB_TokenCRC(void *Data, int len);
+/**
+ * \note X^16 + X15 + X^2 + 1
+ */
+Uint16 USB_DataCRC(void *Data, int len);
+
+// === STRUCTURES ===
+/**
+ * \brief Defines a USB Host Controller
+ */
+struct sUSBHost
+{
+ Uint16 IOBase;
+
+ int (*SendPacket)(int ID, int Length, void *Data);
+};
+
+/**
+ * \brief Defines a single device on the USB Bus
+ */
+struct sUSBDevice
+{
+ tUSBHost *Host;
+ int MaxControl;
+ int MaxBulk;
+ int MaxISync;
+};
+
+#endif
+++ /dev/null
-#
-#
-
-OBJ = main.o uhci.o
-NAME = USB
-
--include ../Makefile.tpl
--- /dev/null
+CATEGORY = USB
+
+-include ../../Makefile.tpl
+++ /dev/null
-/*
- * Acess2
- * USB Stack
- */
-#define VERSION ( (0<<8)| 5 )
-#define DEBUG 1
-#include <acess.h>
-#include <vfs.h>
-#include <fs_devfs.h>
-#include <modules.h>
-#include "usb.h"
-
-// === IMPORTS ===
- int UHCI_Initialise();
-
-// === PROTOTYPES ===
- int USB_Install(char **Arguments);
-void USB_Cleanup();
-char *USB_ReadDir(tVFS_Node *Node, int Pos);
-tVFS_Node *USB_FindDir(tVFS_Node *Node, char *Name);
- int USB_IOCtl(tVFS_Node *Node, int Id, void *Data);
-
-// === GLOBALS ===
-MODULE_DEFINE(0, VERSION, USB, USB_Install, NULL, NULL);
-tDevFS_Driver gUSB_DrvInfo = {
- NULL, "usb", {
- .NumACLs = 1,
- .ACLs = &gVFS_ACL_EveryoneRX,
- .Flags = VFS_FFLAG_DIRECTORY,
- .ReadDir = USB_ReadDir,
- .FindDir = USB_FindDir,
- .IOCtl = USB_IOCtl
- }
-};
-tUSBDevice *gUSB_Devices = NULL;
-tUSBHost *gUSB_Hosts = NULL;
-
-// === CODE ===
-/**
- * \fn int ModuleLoad()
- * \brief Called once module is loaded
- */
-int USB_Install(char **Arguments)
-{
- UHCI_Initialise();
- Warning("[USB ] Not Complete - Devel Only");
- return 1;
-}
-
-/**
- * \fn void USB_Cleanup()
- * \brief Called just before module is unloaded
- */
-void USB_Cleanup()
-{
-}
-
-/**
- * \fn char *USB_ReadDir(tVFS_Node *Node, int Pos)
- * \brief Read from the USB root
- */
-char *USB_ReadDir(tVFS_Node *Node, int Pos)
-{
- return NULL;
-}
-
-/**
- * \fn tVFS_Node *USB_FindDir(tVFS_Node *Node, char *Name)
- * \brief Locate an entry in the USB root
- */
-tVFS_Node *USB_FindDir(tVFS_Node *Node, char *Name)
-{
- return NULL;
-}
-
-/**
- * \brief Handles IOCtl Calls to the USB driver
- */
-int USB_IOCtl(tVFS_Node *Node, int Id, void *Data)
-{
- return 0;
-}
+++ /dev/null
-/*\r
- * Acess 2 USB Stack\r
- * Universal Host Controller Interface\r
- */\r
-#define DEBUG 1\r
-#include <acess.h>\r
-#include <vfs.h>\r
-#include <drv_pci.h>\r
-#include "usb.h"\r
-#include "uhci.h"\r
-\r
-// === CONSTANTS ===\r
-#define MAX_CONTROLLERS 4\r
-#define NUM_TDs 1024\r
-\r
-// === PROTOTYPES ===\r
- int UHCI_Initialise();\r
-void UHCI_Cleanup();\r
- int UHCI_IOCtl(tVFS_Node *node, int id, void *data);\r
- int UHCI_Int_InitHost(tUHCI_Controller *Host);\r
-\r
-// === GLOBALS ===
-//Uint gaFrameList[1024];\r
-tUHCI_TD gaUHCI_TDPool[NUM_TDs];\r
-tUHCI_Controller gUHCI_Controllers[MAX_CONTROLLERS];\r
-\r
-// === CODE ===\r
-/**\r
- * \fn int UHCI_Initialise()\r
- * \brief Called to initialise the UHCI Driver\r
- */\r
-int UHCI_Initialise()\r
-{\r
- int i=0, id=-1;\r
- int ret;\r
- Uint16 base;\r
- \r
- ENTER("");\r
- \r
- // Enumerate PCI Bus, getting a maximum of `MAX_CONTROLLERS` devices\r
- while( (id = PCI_GetDeviceByClass(0x0C03, 0xFFFF, id)) >= 0 && i < MAX_CONTROLLERS )\r
- {\r
- gUHCI_Controllers[i].PciId = id;\r
- // Assign a port range (BAR4, Reserve 32 ports)\r
- base = PCI_AssignPort( id, 4, 0x20 );\r
- gUHCI_Controllers[i].IOBase = base;\r
- \r
- Log("[USB ] Controller PCI #%i: IO Base = 0x%x", id, base);\r
- \r
- // Initialise Host\r
- ret = UHCI_Int_InitHost(&gUHCI_Controllers[i]);\r
- // Detect an error\r
- if(ret != 0) {\r
- LEAVE('i', ret);\r
- return ret;\r
- }\r
- \r
- i ++;\r
- }\r
- if(i == MAX_CONTROLLERS) {\r
- Warning("[UHCI ] Over "EXPAND_STR(MAX_CONTROLLERS)" UHCI controllers detected, ignoring rest");\r
- }\r
- LEAVE('i', i);\r
- return i;\r
-}\r
-\r
-/**\r
- * \fn void UHCI_Cleanup()\r
- * \brief Called just before module is unloaded\r
- */\r
-void UHCI_Cleanup()\r
-{\r
-}
-\r
-/**\r
- * \brief Sends a packet to a device endpoint\r
- */\r
-int UHCI_SendPacket(int ControllerId, int Length)\r
-{\r
- //tUHCI_TD *td = UHCI_AllocateTD();\r
- return 0;\r
-}\r
-\r
-// === INTERNAL FUNCTIONS ===\r
-/**\r
- * \fn int UHCI_Int_InitHost(tUCHI_Controller *Host)\r
- * \brief Initialises a UHCI host controller\r
- * \param Host Pointer - Host to initialise\r
- */\r
-int UHCI_Int_InitHost(tUHCI_Controller *Host)\r
-{\r
- ENTER("pHost", Host);\r
- \r
- // Allocate Frame List\r
- Host->FrameList = (void *) MM_AllocDMA(1, 32, &Host->PhysFrameList); // 1 Page, 32-bit\r
- if( !Host->FrameList ) {\r
- Warning("[UHCI ] Unable to allocate frame list, aborting");\r
- LEAVE('i', -1);\r
- return -1;\r
- }\r
- LOG("Allocated frame list 0x%x (0x%x)", Host->FrameList, Host->PhysFrameList);\r
- memsetd( Host->FrameList, 1, 1024 ); // Clear List (Disabling all entries)\r
- \r
- //! \todo Properly fill frame list\r
- \r
- // Set frame length to 1 ms\r
- outb( Host->IOBase + SOFMOD, 64 );\r
- \r
- // Set Frame List Address\r
- outd( Host->IOBase + FLBASEADD, Host->PhysFrameList );\r
- \r
- // Set Frame Number\r
- outw( Host->IOBase + FRNUM, 0 );\r
- \r
- // Enable Interrupts\r
- //PCI_WriteWord( Host->PciId, 0xC0, 0x2000 );\r
- \r
- LEAVE('i', 0);\r
- return 0;\r
-}\r
+++ /dev/null
-/*
- * AcessOS Version 1
- * USB Stack
- * - Universal Host Controller Interface
- */
-#ifndef _UHCI_H_
-#define _UHCI_H_
-
-// === TYPES ===
-typedef struct sUHCI_Controller tUHCI_Controller;
-typedef struct sUHCI_TD tUHCI_TD;
-typedef struct sUHCI_QH tUHCI_QH;
-
-// === STRUCTURES ===
-struct sUHCI_Controller
-{
- /**
- * \brief PCI Device ID
- */
- Uint16 PciId;
-
- /**
- * \brief IO Base Address
- */
- Uint16 IOBase;
-
- /**
- * \brief Frame list
- *
- * 31:4 - Frame Pointer
- * 3:2 - Reserved
- * 1 - QH/TD Selector
- * 0 - Terminate (Empty Pointer)
- */
- Uint32 *FrameList;
-
- /**
- * \brief Physical Address of the Frame List
- */
- tPAddr PhysFrameList;
-};
-
-struct sUHCI_TD
-{
- /**
- * \brief Next Entry in list
- *
- * 31:4 - Address
- * 3 - Reserved
- * 2 - Depth/Breadth Select
- * 1 - QH/TD Select
- * 0 - Terminate (Last in List)
- */
- Uint32 Link;
-
- /**
- * \brief Control and Status Field
- *
- * 31:30 - Reserved
- * 29 - Short Packet Detect (Input Only)
- * 28:27 - Number of Errors Allowed
- * 26 - Low Speed Device (Communicating with a low speed device)
- * 25 - Isynchonious Select
- * 24 - Interrupt on Completion (IOC)
- * 23:16 - Status
- * 23 - Active
- * 22 - Stalled
- * 21 - Data Buffer Error
- * 20 - Babble Detected
- * 19 - NAK Detected
- * 18 - CRC/Timout Error
- * 17 - Bitstuff Error
- * 16 - Reserved
- * 15:11 - Reserved
- * 10:0 - Actual Length (Number of bytes transfered)
- */
- Uint32 Control;
-
- /**
- * \brief Packet Header
- *
- * 31:21 - Maximum Length (0=1, Max 0x4FF, 0x7FF=0)
- * 20 - Reserved
- * 19 - Data Toggle
- * 18:15 - Endpoint
- * 14:8 - Device Address
- * 7:0 - PID (Packet Identifcation) - Only 96, E1, 2D allowed
- */
- Uint32 Token;
-
- /**
- * \brief Pointer to the data to send
- */
- Uint32 BufferPointer;
-};
-
-struct sUHCI_QH
-{
- /**
- * \brief Next Entry in list
- *
- * 31:4 - Address
- * 3:2 - Reserved
- * 1 - QH/TD Select
- * 0 - Terminate (Last in List)
- */
- Uint32 Next;
-
-
- /**
- * \brief Next Entry in list
- *
- * 31:4 - Address
- * 3:2 - Reserved
- * 1 - QH/TD Select
- * 0 - Terminate (Last in List)
- */
- Uint32 Child;
-};
-
-// === ENUMERATIONS ===
-enum eUHCI_IOPorts {
- /**
- * \brief USB Command Register
- *
- * 15:8 - Reserved
- * 7 - Maximum Packet Size selector (1: 64 bytes, 0: 32 bytes)
- * 6 - Configure Flag (No Hardware Effect)
- * 5 - Software Debug (Don't think it will be needed)
- * 4 - Force Global Resume
- * 3 - Enter Global Suspend Mode
- * 2 - Global Reset (Resets all devices on the bus)
- * 1 - Host Controller Reset (Reset just the controller)
- * 0 - Run/Stop
- */
- USBCMD = 0x00,
- /**
- * \brief USB Status Register
- *
- * 15:6 - Reserved
- * 5 - HC Halted, set to 1 when USBCMD:RS is set to 0
- * 4 - Host Controller Process Error (Errors related to the bus)
- * 3 - Host System Error (Errors related to the OS/PCI Bus)
- * 2 - Resume Detect (Set if a RESUME command is sent to the Controller)
- * 1 - USB Error Interrupt
- * 0 - USB Interrupts (Set if a transaction with the IOC bit set is completed)
- */
- USBSTS = 0x02,
- /**
- * \brief USB Interrupt Enable Register
- *
- * 15:4 - Reserved
- * 3 - Short Packet Interrupt Enable
- * 2 - Interrupt on Complete (IOC) Enable
- * 1 - Resume Interrupt Enable
- * 0 - Timout / CRC Error Interrupt Enable
- */
- USBINTR = 0x04,
- /**
- * \brief Frame Number (Index into the Frame List)
- *
- * 15:11 - Reserved
- * 10:0 - Index (Incremented each approx 1ms)
- */
- FRNUM = 0x06,
- /**
- * \brief Frame List Base Address
- *
- * 31:12 - Pysical Address >> 12
- * 11:0 - Reserved (Set to Zero)
- */
- FLBASEADD = 0x08, // 32-bit
- /**
- * \brief Start-of-frame Modify Register
- * \note 8-bits only
- *
- * Sets the size of a frame
- * Frequency = (11936+n)/12000 kHz
- *
- * 7 - Reserved
- * 6:0 -
- */
- SOFMOD = 0x0C, // 8bit
- /**
- * \brief Port Status and Controll Register (Port 1)
- *
- * 15:13 - Reserved
- * 12 - Suspend
- * 11:10 - Reserved
- * 9 - Port Reset
- * 8 - Low Speed Device Attached
- * 5:4 - Line Status
- * 3 - Port Enable/Disable Change - Used for detecting device removal
- * 2 - Port Enable/Disable
- * 1 - Connect Status Change
- * 0 - Current Connect Status
- */
- PORTSC1 = 0x10,
- /**
- * \brief Port Status and Controll Register (Port 2)
- *
- * See ::PORTSC1
- */
- PORTSC2 = 0x12
-};
-
-#endif
+++ /dev/null
-/*
- * Acess 2 USB Stack
- * USB Packet Control
- */
-#define DEBUG 1
-#include <acess.h>
-#include <vfs.h>
-#include <drv_pci.h>
-#include "usb.h"
-
-
-// === CODE ===
-void USB_MakeToken(void *Buf, int PID, int Addr, int EndP)
-{
- Uint8 *tok = Buf;
- int crc = 0; //USB_TokenCRC();
-
- tok[0] = PID;
- tok[1] = Addr | ((EndP&1)<<7);
- tok[2] = (EndP >> 1) | crc;
-}
-
-#if 0
-void USB_SendPacket(int Controller, int PID, int Dev, int Endpoint, void *Data, int Length)
-{
- uint8_t buf[Length/*+??*/];
- switch(Controller & 0xF00)
- {
- case 1:
- UHCI_SendPacket(Controller & 0xFF);
- }
-}
-#endif
+++ /dev/null
-/*
- * AcessOS Version 1
- * USB Stack
- */
-#ifndef _USB_H_
-#define _USB_H_
-
-// === TYPES ===
-typedef struct sUSBHost tUSBHost;
-typedef struct sUSBDevice tUSBDevice;
-
-// === CONSTANTS ===
-enum eUSB_PIDs
-{
- /**
- * \name Token
- * \{
- */
- PID_OUT = 0xE1,
- PID_IN = 0x69,
- PID_SOF = 0xA5,
- PID_SETUP = 0x2D,
- /**
- * \}
- */
-
- /**
- * \name Data
- * \{
- */
- PID_DATA0 = 0xC3,
- PID_DATA1 = 0x4B,
- PID_DATA2 = 0x87, // USB2 only
- PID_MDATA = 0x0F, // USB2 only
- /**
- * \}
- */
-
- /**
- * \name Handshake
- * \{
- */
- PID_ACK = 0xD2,
- PID_NAK = 0x5A,
- PID_STALL = 0x1E,
- PID_NYET = 0x96,
- /**
- * \}
- */
-
- /**
- * \name Special
- * \{
- */
- PID_PRE = 0x3C, PID_ERR = 0x3C,
- PID_SPLIT = 0x78,
- PID_PING = 0xB4,
- PID_RESVD = 0xF0,
- /**
- * \}
- */
-};
-
-// === FUNCTIONS ===
-/**
- * \note 00101 - X^5+X^2+1
- */
-Uint8 USB_TokenCRC(void *Data, int len);
-/**
- * \note X^16 + X15 + X^2 + 1
- */
-Uint16 USB_DataCRC(void *Data, int len);
-
-// === STRUCTURES ===
-/**
- * \brief Defines a USB Host Controller
- */
-struct sUSBHost
-{
- Uint16 IOBase;
-
- int (*SendPacket)(int ID, int Length, void *Data);
-};
-
-/**
- * \brief Defines a single device on the USB Bus
- */
-struct sUSBDevice
-{
- tUSBHost *Host;
-};
-
-#endif
-include ../Makefile.cfg\r
\r
CPPFLAGS += -I./include\r
+LDFLAGS += -lreadline\r
\r
BIN = ../CLIShell\r
OBJ = main.o lib.o\r
/*\r
* AcessOS Shell Version 3\r
*/\r
+#define USE_READLINE 0\r
#include <acess/sys.h>\r
#include <stdlib.h>\r
#include <stdio.h>\r
#include <string.h>\r
#include "header.h"\r
\r
+#if USE_READLINE\r
+# include "readline.h"\r
+#endif\r
+\r
#define _stdin 0\r
#define _stdout 1\r
#define _stderr 2\r
int length = 0;\r
int i;\r
int iArgCount = 0;\r
+ #if !USE_READLINE\r
int bCached = 1;\r
+ #else\r
+ tReadline readline_state = {0};\r
+ #endif\r
+ \r
+ #if USE_READLINE\r
+ readline_state.UseHistory = 1;\r
+ #endif\r
\r
gasEnvironment = envp;\r
\r
{\r
// Free last command & arguments\r
if(saArgs[0]) free(saArgs);\r
+ #if !USE_READLINE\r
if(!bCached) free(sCommandStr);\r
bCached = 0;\r
+ #endif\r
\r
write(_stdout, strlen(gsCurrentDirectory), gsCurrentDirectory);\r
write(_stdout, 2, "$ ");\r
\r
// Read Command line\r
+ #if USE_READLINE\r
+ sCommandStr = Readline( &readline_state );\r
+ length = strlen(sCommandStr);\r
+ #else\r
sCommandStr = ReadCommandLine( &length );\r
\r
if(!sCommandStr) {\r
gasCommandHistory[ giLastCommand ] = sCommandStr;\r
bCached = 1;\r
}\r
+ #endif\r
\r
// Parse Command Line into arguments\r
Parse_Args(sCommandStr, saArgs);\r
\r
// Shall we?\r
CallCommand( &saArgs[1] );\r
+ \r
+ #if USE_READLINE\r
+ free( sCommandStr );\r
+ #endif\r
}\r
}\r
\r
--- /dev/null
+# Project: Acess GUI Default Shell
+
+-include ../../Makefile.cfg
+
+CPPFLAGS += -I../include
+LDFLAGS += -laxwin2
+
+DIR = Apps/AxWin/1.0
+BIN = ../Shell
+OBJ = main.o
+
+-include ../../Makefile.tpl
--- /dev/null
+/*
+ * Acess2 GUI Shell
+ * - By John Hodge (thePowersGang)
+ */
+#include <axwin/axwin.h>
+
+// === PROTOTYPES ===
+ int main(int argc, char *argv[]);
+ int Menubar_HandleMessage(tAxWin_Message *Message);
+
+// === GLOBALS ===
+tAxWin_Handle ghMenubarWindow;
+
+// === CODE ===
+int main(int argc, char *argv[])
+{
+ // Create Window
+ ghMenubarWindow = AxWin_CreateWindow(0, 0, -1, -1, WINFLAG_NOBORDER, Menubar_HandleMessage);
+
+ AxWin_MessageLoop();
+
+ return 0;
+}
+
+/**
+ */
+int Menubar_HandleMessage(tAxWin_Message *Message)
+{
+ return 0;
+}
#include <stdio.h>
#include <stdint.h>
+#include "wm.h"
+
+// === GLOBALS ===
extern char *gsTerminalDevice;
extern char *gsMouseDevice;
--- /dev/null
+
+#ifndef _WM_H_
+#define _WM_H_
+
+typedef struct sElement
+{
+ struct sElement *NextSibling;
+
+ short CachedX;
+ short CachedY;
+ short CachedW;
+ short CachedH;
+
+ struct sElement *FirstChild;
+} tElement;
+
+typedef struct sTab
+{
+ char *Name;
+
+ tElement *RootElement;
+} tTab;
+
+typedef struct sApplication
+{
+ pid_t PID;
+
+ int nTabs;
+ tTab *Tabs;
+
+ char Name[];
+} tApplication;
+
+#endif
type = ioctl(fd, 4, NULL);
printf("%s:\t", filename);
+ {
+ int len = ioctl(fd, ioctl(fd, 3, "get_device"), NULL);
+ char *buf = malloc(len+1);
+ ioctl(fd, ioctl(fd, 3, "get_device"), buf);
+ printf("'%s'\t", buf);
+ free(buf);
+ }
switch(type)
{
case 0:
#include <stdio.h>
#define MOUNTABLE_FILE "/Acess/Conf/Mountable"
-#define MOUNTED_FILE "/Acess/Conf/Mounted"
+#define MOUNTED_FILE "/Devices/System/VFS/Mounts"
// === PROTOTYPES ===
void ShowUsage();
- int GetMountDefs(char **spDevice, char **spDir, char **spType, char **spOptions);
+ int GetMountDefs(char *Ident, char **spDevice, char **spDir, char **spType, char **spOptions);
// === CODE ===
/**
{
switch(arg[1])
{
+ // -t <driver> :: Filesystem driver to use
case 't': sType = argv[++i]; break;
case '-':
//TODO: Long Arguments
continue;
}
+ // Device?
if(sDevice == NULL) {
sDevice = arg;
continue;
}
+ // Directory?
if(sDir == NULL) {
sDir = arg;
continue;
if(sDir == NULL || getuid() != 0)
{
// Check if it is defined in the mounts file
- if(GetMountDefs(&sDevice, &sDir, &sType, &sOptions) == 0)
+ // - At this point sDevice could be a device name or a mount point
+ if(GetMountDefs(sDevice, &sDevice, &sDir, &sType, &sOptions) == 0)
{
if(sDir == NULL)
fprintf(stderr, "Unable to find '%s' in '%s'\n",
}
/**
- * \fn int GetMountDefs(char **spDevice, char **spDir, char **spType, char **spOptions)
+ * \fn int GetMountDefs(char *Ident, char **spDevice, char **spDir, char **spType, char **spOptions)
* \brief Reads the mountable definitions file and returns the corresponding entry
* \param spDevice Pointer to a string (pointer) determining the device (also is the input for this function)
* \note STUB
*/
-int GetMountDefs(char **spDevice, char **spDir, char **spType, char **spOptions)
+int GetMountDefs(char *Ident, char **spDevice, char **spDir, char **spType, char **spOptions)
{
// TODO: Read the mounts file (after deciding what it will be)
return 0;
-module /Acess/Modules/bochsvbe.kmd
+#module /Acess/Modules/bochsvbe.kmd
#module /Acess/Modules/ps2mouse
#edimod /Acess/Modules/serial.edi
#module /Acess/Modules/ne2000.akm
--- /dev/null
+# Acess 2 SQLite 3 Library
+#
+
+.PHONY: all clean install
+
+all: $(BIN)
+
+clean:
+ $(RM) $(BIN) $(OBJ)
+
+install: $(BIN)
+ $(xCP) $(BIN) $(DISTROOT)/Libs/
+
+$(BIN): $(OBJ)
+ $(LD) $(LDFLAGS) -o $(BIN) $(OBJ)
+
+%.o: %.c
+ $(CC) $(CFLAGS) -o $@ -c $<
#
#
-AS = nasm
-RM = rm -f
+-include ../Makefile.cfg
ASFLAGS = -felf
\r
// Create Temp Name\r
filename = FindLibrary(sTmpName, SoName, SearchDir);\r
+ if(filename == NULL) {\r
+ DEBUGS("LoadLibrary: RETURN 0\n");\r
+ return 0;\r
+ }\r
DEBUGS(" LoadLibrary: filename='%s'\n", filename);\r
\r
if( (iArg = IsFileLoaded(filename)) )\r
--- /dev/null
+# Acess 2 - AxWin GUI Library
+#
+
+include ../Makefile.cfg
+
+CPPFLAGS +=
+CFLAGS += -Wall
+LDFLAGS += -lc -soname libaxwin2.so
+
+OBJ = main.o messages.o windows.o
+BIN = ../libaxwin2.so
+
+include ../Makefile.tpl
--- /dev/null
+/*
+ * AxWin Window Manager Interface Library
+ * By John Hodge (thePowersGang)
+ * This file is published under the terms of the Acess Licence. See the
+ * file COPYING for details.
+ *
+ * common.h - Internal Variable and Constant definitions
+ */
+#ifndef _COMMON_H_
+#define _COMMON_H_
+
+// === Includes ===
+#include <acess/sys.h>
+#include <axwin/axwin.h>
+#include <stdlib.h>
+
+// === Constants ===
+enum eAxWin_Modes
+{
+ AXWIN_MODE_IPC
+};
+
+// === Variables ===
+extern int giAxWin_Mode;
+
+#endif
--- /dev/null
+/*
+ * AxWin Window Manager Interface Library
+ * By John Hodge (thePowersGang)
+ * This file is published under the terms of the Acess Licence. See the
+ * file COPYING for details.
+ *
+ * main.c - Library Initialisation
+ */
+#include "common.h"
+
+// === GLOBALS ===
+ int giAxWin_Mode = 0;
+
+// === CODE ===
+int SoMain()
+{
+ return 0;
+}
--- /dev/null
+/*
+ * AxWin Window Manager Interface Library
+ * By John Hodge (thePowersGang)
+ * This file is published under the terms of the Acess Licence. See the
+ * file COPYING for details.
+ *
+ * messages.c - Message Handling
+ */
+#include "common.h"
+
+// === PROTOTYPES ===
+ int AxWin_MessageLoop();
+tAxWin_Message *AxWin_WaitForMessage();
+ int AxWin_HandleMessage(tAxWin_Message *Message);
+
+// === CODE ===
+/**
+ * \brief Loop forever, checking and waiting for messages
+ */
+int AxWin_MessageLoop()
+{
+ tAxWin_Message *msg;
+ int ret;
+ for(;;)
+ {
+ msg = AxWin_WaitForMessage();
+ ret = AxWin_HandleMessage(msg);
+
+ if(ret < 0) return 0;
+ }
+ return 0;
+}
+
+/**
+ * \brief Wait for a message
+ */
+tAxWin_Message *AxWin_WaitForMessage()
+{
+ int length;
+ pid_t src;
+ tAxWin_Message *ret;
+
+ switch( giAxWin_Mode )
+ {
+ case AXWIN_MODE_IPC:
+ while( (length = SysGetMessage(&src, NULL)) == 0 ) sleep();
+ ret = malloc(length);
+ SysGetMessage(NULL, ret);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+/**
+ * \brief Handles a recieved message
+ */
+int AxWin_HandleMessage(tAxWin_Message *Message)
+{
+ switch(Message->ID)
+ {
+ default: return 0;
+ }
+}
--- /dev/null
+/*
+ * AxWin Window Manager Interface Library
+ * By John Hodge (thePowersGang)
+ * This file is published under the terms of the Acess Licence. See the
+ * file COPYING for details.
+ *
+ * window.c - Window Control
+ */
+#include "common.h"
+
+// === TYPES & STRUCTURES ===
+struct sAxWin_Window
+{
+ struct sAxWin_Window *Next;
+ uint32_t WmHandle;
+ tAxWin_MessageCallback Callback;
+};
+
+// === PROTOTYPES ===
+tAxWin_Handle AxWin_CreateWindow(
+ int16_t X, int16_t Y, int16_t W, int16_t H,
+ uint32_t Flags, tAxWin_MessageCallback *Callback
+ );
+
+// === GLOBALS ===
+//mutex_t glProcessWindows;
+tAxWin_Window *gProcessWindows;
+
+// === CODE ===
+tAxWin_Handle AxWin_CreateWindow(
+ int16_t X, int16_t Y,
+ int16_t W, int16_t H,
+ uint32_t Flags, tAxWin_MessageCallback *Callback)
+{
+ tAxWin_Message req;
+ tAxWin_Message *msg;
+ tAxWin_Window *win;
+
+ req.ID = MSG_SREQ_NEWWINDOW;
+ req.Size = 1 + sizeof(struct sAxWin_SReq_NewWindow)/4;
+ req.SReq_NewWindow.X = X;
+ req.SReq_NewWindow.Y = Y;
+ req.SReq_NewWindow.W = W;
+ req.SReq_NewWindow.H = H;
+ req.SReq_NewWindow.Flags = Flags;
+
+ AxWin_SendMessage(&msg);
+
+ for(;;)
+ {
+ msg = AxWin_WaitForMessage();
+
+ if(msg.ID == MSG_SRSP_WINDOW)
+ break;
+
+ AxWin_HandleMessage(msg);
+ free(msg);
+ }
+
+ win = malloc(sizeof(tAxWin_Window));
+ win->WmHandle = msg->SRsp_Window.Handle;
+ win->Callback = Callback;
+
+ //mutex_acquire(glProcessWindows);
+ win->Next = gProcessWindows;
+ gProcessWindows = win;
+ //mutex_release(glProcessWindows);
+
+ return 0;
+}
--- /dev/null
+# Acess 2 - AxWin GUI Library
+#
+
+include ../Makefile.cfg
+
+CPPFLAGS +=
+CFLAGS += -Wall
+LDFLAGS += -lc -soname libreadline.so
+
+OBJ = main.o
+BIN = ../libreadline.so
+
+include ../Makefile.tpl
* Text mode entry with history
*/
#include <readline.h>
+#include <acess/sys.h>
#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define STDIN_FD 0
+#define STDOUT_FD 1
+
+// === PROTOTYPES ===
+ int SoMain();
+tReadline *Readline_CreateInstance(int bUseHistory);
+char *Readline(tReadline *Info);
// === GLOBALS ===
// === CODE ===
+int SoMain()
+{
+ return 0;
+}
+
char *Readline(tReadline *Info)
{
char *ret;
+ char *orig;
int len, pos, space = 1023-8-8; // optimised for the heap manager
char ch;
int scrollbackPos = Info->NumHistory;
ret = malloc( space+1 );
if(!ret) return NULL;
len = 0; pos = 0;
-
+
+ orig = ret;
+
// Read In Command Line
do {
- read(_stdin, 1, &ch); // Read Character from stdin (read is a blocking call)
+ read(STDIN_FD, 1, &ch); // Read Character from stdin (read is a blocking call)
if(ch == '\n') break;
{
// Control characters
case '\x1B':
- read(_stdin, 1, &ch); // Read control character
+ read(STDIN_FD, 1, &ch); // Read control character
switch(ch)
{
//case 'D': if(pos) pos--; break;
//case 'C': if(pos<len) pos++; break;
case '[':
- read(_stdin, 1, &ch); // Read control character
+ read(STDIN_FD, 1, &ch); // Read control character
switch(ch)
{
case 'A': // Up
int oldLen = len;
if( scrollbackPos <= 0 ) break;
- free(ret);
+ if(ret != orig) free(ret);
ret = strdup( Info->History[--scrollbackPos] );
- len = strlen(ret);
- while(pos--) write(_stdout, 3, "\x1B[D");
- write(_stdout, len, ret); pos = len;
- while(pos++ < oldLen) write(_stdout, 1, " ");
+ space = len = strlen(ret);
+ while(pos-->1) write(STDOUT_FD, 3, "\x1B[D");
+ write(STDOUT_FD, len, ret); pos = len;
+ while(pos++ < oldLen) write(STDOUT_FD, 1, " ");
}
break;
case 'B': // Down
int oldLen = len;
if( scrollbackPos >= Info->NumHistory ) break;
- free(ret);
+ if(ret != orig) free(ret);
ret = strdup( Info->History[scrollbackPos++] );
- len = strlen(ret);
- while(pos--) write(_stdout, 3, "\x1B[D");
- write(_stdout, len, ret); pos = len;
- while(pos++ < oldLen) write(_stdout, 1, " ");
+ space = len = strlen(ret);
+ while(pos-->1) write(STDOUT_FD, 3, "\x1B[D");
+ write(STDOUT_FD, len, ret); pos = len;
+ while(pos++ < oldLen) write(STDOUT_FD, 1, " ");
}
break;
case 'D': // Left
if(pos == 0) break;
pos --;
- write(_stdout, 3, "\x1B[D");
+ write(STDOUT_FD, 3, "\x1B[D");
break;
case 'C': // Right
if(pos == len) break;
pos++;
- write(_stdout, 3, "\x1B[C");
+ write(STDOUT_FD, 3, "\x1B[C");
break;
}
}
// Backspace
case '\b':
if(len <= 0) break; // Protect against underflows
- write(_stdout, 1, &ch);
+ write(STDOUT_FD, 1, &ch);
if(pos == len) { // Simple case of end of string
len --;
pos--;
buf[2] += ((len-pos+1)/100) % 10;
buf[3] += ((len-pos+1)/10) % 10;
buf[4] += (len-pos+1) % 10;
- write(_stdout, len-pos, &ret[pos]); // Move Text
- ch = ' '; write(_stdout, 1, &ch); ch = '\b'; // Clear deleted character
- write(_stdout, 7, buf); // Update Cursor
+ write(STDOUT_FD, len-pos, &ret[pos]); // Move Text
+ ch = ' '; write(STDOUT_FD, 1, &ch); ch = '\b'; // Clear deleted character
+ write(STDOUT_FD, 7, buf); // Update Cursor
// Alter Buffer
memmove(&ret[pos-1], &ret[pos], len-pos);
pos --;
// Expand Buffer
if(len+1 > space) {
space += 256;
- ret = realloc(ret, space+1);
+ if(ret == orig) {
+ orig = ret = realloc(ret, space+1);
+ }
+ else {
+ ret = realloc(ret, space+1);
+ }
if(!ret) return NULL;
}
buf[2] += ((len-pos)/100) % 10;
buf[3] += ((len-pos)/10) % 10;
buf[4] += (len-pos) % 10;
- write(_stdout, 1, &ch); // Print new character
- write(_stdout, len-pos, &ret[pos]); // Move Text
- write(_stdout, 7, buf); // Update Cursor
+ write(STDOUT_FD, 1, &ch); // Print new character
+ write(STDOUT_FD, len-pos, &ret[pos]); // Move Text
+ write(STDOUT_FD, 7, buf); // Update Cursor
memmove( &ret[pos+1], &ret[pos], len-pos );
}
else {
- write(_stdout, 1, &ch);
+ write(STDOUT_FD, 1, &ch);
}
ret[pos++] = ch;
len ++;
// Add to history
if( Info->UseHistory )
{
- if( strcmp( Info->History[ Info->NumHistory-1 ], ret) != 0 )
+ if( !Info->History || strcmp( Info->History[ Info->NumHistory-1 ], ret) != 0 )
{
void *tmp;
Info->NumHistory ++;
}
}
+ if(ret != orig) free(orig);
+
return ret;
}
--- /dev/null
+/**
+ * \file axwin.h
+ * \author John Hodge (thePowersGang)
+ * \brief AxWin Core functions
+ */
+#ifndef _AXWIN_AXWIN_H
+#define _AXWIN_AXWIN_H
+
+// === Core Types ===
+typedef unsigned int tAxWin_Handle;
+
+// === Messaging ===
+#include "messages.h"
+extern int AxWin_MessageLoop();
+
+// === Window Control ===
+/**
+ * \brief Window Type
+ * \note Opaque Type
+ */
+typedef struct sAxWin_Window tAxWin_Window;
+
+typedef int tAxWin_MessageCallback(tAxWin_Message *);
+
+/**
+ * \brief Window Flags
+ * \{
+ */
+#define WINFLAG_NOBORDER 0x100
+/**
+ * \}
+ */
+extern tAxWin_Window AxWin_CreateWindow(
+ int16_t X, int16_t Y, int16_t W, int16_t H,
+ uint32_t Flags, tAxWin_MessageCallback *Callback);
+
+#endif
// Server Requests
MSG_SREQ_PING,
// - Windows
- MSG_SREQ_NEWWINDOW, // (short x, y, w, h, uint32_t flags)
- MSG_SREQ_GETFLAGS, MSG_SREQ_SETFLAGS,
- MSG_SREQ_GETRECT, MSG_SREQ_SETRECT,
+ MSG_SREQ_REGISTER, // bool (char[] Name) - Registers this PID with the Window Manager
+
+ MSG_SREQ_ADDTAB, // ELEMENT (char[] Name) - Adds a tab to the window
+ MSG_SREQ_DELTAB, // void (TAB Tab) - Closes a tab
+
+ MSG_SREQ_NEWDIALOG, // ELEMENT (ELEMENT Parent, char[] Name) - Creates a dialog
+ MSG_SREQ_DELDIALOG, // void (ELEMENT Dialog) - Closes a dialog
+
+ MSG_SREQ_SETNAME, // void (ELEMENT Element, char[] Name)
+ MSG_SREQ_GETNAME, // char[] (ELEMENT Element)
+
+ // - Builtin Elements
+ MSG_SREQ_INSERT, // void (ELEMENT Parent, eAxWin_Controls Type, u32 Flags)
+
// - Drawing
+ // All drawing functions take an ELEMENT as their first parameter.
+ // This must be either a Tab, Dialog or Canvas control
MSG_SREQ_SETCOL,
MSG_SREQ_PSET,
MSG_SREQ_LINE, MSG_SREQ_CURVE,
MSG_SREQ_SETFONT, MSG_SREQ_PUTTEXT,
// Server Responses
- MSG_SRSP_PONG,
- MSG_SRSP_WINDOW, // Returns the new window ID
- MSG_SRSP_IMG, // Returns the image ID
+ MSG_SRSP_RETURN, // {int RequestID, void[] Return Value} - Returns a value from a server request
NUM_MSG
};
--- /dev/null
+/*
+ * Acess2 Library Suite
+ * - Readline
+ *
+ * Text mode entry with history
+ */
+#ifndef _READLINE_H_
+#define _READLINE_H_
+
+// === TYPES ===
+typedef struct sReadline tReadline;
+
+// === STRUCTURES ===
+struct sReadline
+{
+ int UseHistory; // Boolean
+
+ int NumHistory;
+ char **History;
+};
+
+// === FUNCTIONS ===
+/**
+ * \brief Read a line from stdin
+ */
+extern char *Readline(tReadline *Info);
+
+#endif