From: John Hodge Date: Mon, 13 Feb 2012 10:18:26 +0000 (+0800) Subject: Kernel/timers - Cleaning up timer code... might have made more mess X-Git-Tag: rel0.15~778 X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;h=934d0f535e1929fd90ae0606e77794484aa55284;p=tpg%2Facess2.git Kernel/timers - Cleaning up timer code... might have made more mess - Moved callbacks into a worker thread - BUG: Possibly some race conditions causing lockups - Re-enabled preemption :) - Fixed workqueue not setting ->Next to NULL --- diff --git a/KernelLand/Kernel/arch/x86/errors.c b/KernelLand/Kernel/arch/x86/errors.c index d2d2cef1..f0f6e2b2 100644 --- a/KernelLand/Kernel/arch/x86/errors.c +++ b/KernelLand/Kernel/arch/x86/errors.c @@ -80,7 +80,6 @@ void ErrorHandler(tRegs *Regs) // Page Fault if(Regs->int_num == 14) { - __asm__ __volatile__ ("sti"); // Should be OK, TODO: Test __asm__ __volatile__ ("mov %%cr2, %0":"=r"(cr)); MM_PageFault( cr, Regs->err_code, Regs ); return ; diff --git a/KernelLand/Kernel/arch/x86/kpanic.c b/KernelLand/Kernel/arch/x86/kpanic.c index 9300c69e..3e2ccacc 100644 --- a/KernelLand/Kernel/arch/x86/kpanic.c +++ b/KernelLand/Kernel/arch/x86/kpanic.c @@ -78,6 +78,8 @@ const struct { void KernelPanic_SetMode(void) { int i; + + __asm__ __volatile__ ("cli"); // Stop the processor! // This function is called by Panic(), but MM_PageFault and the // CPU exception handers also call it, so let's not clear the screen diff --git a/KernelLand/Kernel/arch/x86/mm_virt.c b/KernelLand/Kernel/arch/x86/mm_virt.c index bd7b1dff..c17b57bd 100644 --- a/KernelLand/Kernel/arch/x86/mm_virt.c +++ b/KernelLand/Kernel/arch/x86/mm_virt.c @@ -171,6 +171,7 @@ void MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs) && gaPageTable[Addr>>12] & PF_COW ) { tPAddr paddr; + __asm__ __volatile__ ("sti"); if(MM_GetRefCount( gaPageTable[Addr>>12] & ~0xFFF ) == 1) { gaPageTable[Addr>>12] &= ~PF_COW; @@ -197,6 +198,7 @@ void MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs) // If it was a user, tell the thread handler if(ErrorCode & 4) { + __asm__ __volatile__ ("sti"); Log_Warning("MMVirt", "User %s %s memory%s", (ErrorCode&2?"write to":"read from"), (ErrorCode&1?"bad/locked":"non-present"), diff --git a/KernelLand/Kernel/arch/x86/proc.c b/KernelLand/Kernel/arch/x86/proc.c index 82a3f409..8d856086 100644 --- a/KernelLand/Kernel/arch/x86/proc.c +++ b/KernelLand/Kernel/arch/x86/proc.c @@ -35,6 +35,7 @@ typedef struct sCPU Uint8 State; // 0: Unavaliable, 1: Idle, 2: Active Uint16 Resvd; tThread *Current; + tThread *LastTimerThread; // Used to do preeemption } tCPU; // === IMPORTS === @@ -939,6 +940,7 @@ void Proc_Reschedule(void) // Update CPU state gaCPUs[cpu].Current = nextthread; + gaCPUs[cpu].LastTimerThread = NULL; gTSSs[cpu].ESP0 = nextthread->KernelStack-4; __asm__ __volatile__("mov %0, %%db0\n\t" : : "r"(nextthread) ); @@ -976,49 +978,14 @@ void Proc_Reschedule(void) */ void Proc_Scheduler(int CPU) { -#if 0 - tThread *thread; - - // If the spinlock is set, let it complete - if(IS_LOCKED(&glThreadListLock)) return; - - // Get current thread - thread = gaCPUs[CPU].Current; - - if( thread ) + // If two ticks happen within the same task, and it's not an idle task, swap + if( gaCPUs[CPU].Current->TID > giNumCPUs && gaCPUs[CPU].Current == gaCPUs[CPU].LastTimerThread ) { - tRegs *regs; - Uint ebp; - // Reduce remaining quantum and continue timeslice if non-zero - if( thread->Remaining-- ) - return; - // Reset quantum for next call - thread->Remaining = thread->Quantum; - - // TODO: Make this more stable somehow - __asm__ __volatile__("mov %%ebp, %0" : "=r" (ebp)); - regs = (tRegs*)(ebp+(2+2)*4); // EBP,Ret + CPU,CurThread - thread->SavedState.UserCS = regs->cs; - thread->SavedState.UserEIP = regs->eip; - - if(thread->bInstrTrace) { - regs->eflags |= 0x100; // Set TF - Log("%p De-scheduled", thread); - } - else - regs->eflags &= ~0x100; // Clear TF + Proc_Reschedule(); } - - // TODO: Ack timer? - #if USE_MP - if( GetCPUNum() ) - gpMP_LocalAPIC->EOI.Val = 0; - else - #endif - outb(0x20, 0x20); - __asm__ __volatile__ ("sti"); - Proc_Reschedule(); -#endif + gaCPUs[CPU].LastTimerThread = gaCPUs[CPU].Current; + // Call the timer update code + Timer_CallTimers(); } // === EXPORTS === diff --git a/KernelLand/Kernel/debug.c b/KernelLand/Kernel/debug.c index 355624d5..25ffda19 100644 --- a/KernelLand/Kernel/debug.c +++ b/KernelLand/Kernel/debug.c @@ -9,7 +9,7 @@ #define DEBUG_MAX_LINE_LEN 256 -#define LOCK_DEBUG_OUTPUT 1 +#define LOCK_DEBUG_OUTPUT 0 #define TRACE_TO_KTERM 0 diff --git a/KernelLand/Kernel/include/acess.h b/KernelLand/Kernel/include/acess.h index 2cd2cff1..0121eb24 100644 --- a/KernelLand/Kernel/include/acess.h +++ b/KernelLand/Kernel/include/acess.h @@ -15,6 +15,8 @@ #define PACKED __attribute__((packed)) //! Mark a function as not returning #define NORETURN __attribute__((noreturn)) +//! Mark a function (or variable) as deprecated +#define DEPRECATED __attribute__((deprecated)) //! Mark a parameter as unused #define UNUSED(x) UNUSED_##x __attribute__((unused)) //! Get the offset of a member in a structure @@ -182,7 +184,7 @@ extern void Debug_HexDump(const char *Header, const void *Data, Uint Length); # define LEAVE_RET0() return #endif #if SANITY -# define ASSERT(expr) do{if(!(expr))Panic("%s: Assertion '"#expr"' failed",(char*)__func__);}while(0) +# define ASSERT(expr) do{if(!(expr))Panic("%s:%i - %s: Assertion '"#expr"' failed",__FILE__,__LINE__,(char*)__func__);}while(0) #else # define ASSERT(expr) #endif diff --git a/KernelLand/Kernel/include/timers.h b/KernelLand/Kernel/include/timers.h index 22dd5c6a..c43c4016 100644 --- a/KernelLand/Kernel/include/timers.h +++ b/KernelLand/Kernel/include/timers.h @@ -25,11 +25,34 @@ typedef void (tTimerCallback)(void *); * \param Callback Function to call each time * \param Argument Argument to pass to the callback */ -extern tTimer *Time_CreateTimer(int Delta, tTimerCallback *Callback, void *Argument); +extern tTimer *Time_CreateTimer(int Delta, tTimerCallback *Callback, void *Argument) DEPRECATED; + +/** + * \brief Allocate (but don't schedule) a timer object + * \param Callback Function to call (if NULL, EVENT_TIMER is delivered to the current thread) + * \param Argument Argument passed to \a Callback (ignored if \a Callback is NULL) + * \return New timer pointer + */ +extern tTimer *Time_AllocateTimer(tTimerCallback *Callback, void *Argument); + +/** + * \brief Free an allocated timer object + * \param Timer Object pointer returned by Time_AllocateTimer + */ +extern void Time_FreeTimer(tTimer *Timer); + +/** + * \brief Schedules a timer to fire in \a Delta ms + * \param Timer Timer object returned by Time_AllocateTimer + * \param Delta Time until timer fires (in milliseconds) + */ +extern void Time_ScheduleTimer(tTimer *Timer, int Delta); + /** * \brief Removed an active timer */ extern void Time_RemoveTimer(tTimer *Timer); + /** * \brief Wait for a period of milliseconds */ diff --git a/KernelLand/Kernel/system.c b/KernelLand/Kernel/system.c index 8fc2a1cc..d8eba833 100644 --- a/KernelLand/Kernel/system.c +++ b/KernelLand/Kernel/system.c @@ -12,6 +12,7 @@ extern void Arch_LoadBootModules(void); extern int Modules_LoadBuiltins(void); extern void Modules_SetBuiltinParams(char *Name, char *ArgString); extern void Debug_SetKTerminal(const char *File); +extern void Timer_CallbackThread(void *); // === PROTOTYPES === void System_Init(char *Commandline); @@ -29,6 +30,8 @@ char *argv[32]; // === CODE === void System_Init(char *CommandLine) { + Proc_SpawnWorker(Timer_CallbackThread, NULL); + // Parse Kernel's Command Line System_ParseCommandLine(CommandLine); diff --git a/KernelLand/Kernel/threads.c b/KernelLand/Kernel/threads.c index 956eede8..5e60c461 100644 --- a/KernelLand/Kernel/threads.c +++ b/KernelLand/Kernel/threads.c @@ -926,7 +926,6 @@ tThread *Threads_RemActive(void) ret->Next = NULL; ret->Remaining = 0; - giNumActiveThreads --; // no need to decrement tickets, scheduler did it for us #if SCHEDULER_TYPE == SCHED_LOTTERY && DEBUG_TRACE_TICKETS @@ -936,6 +935,7 @@ tThread *Threads_RemActive(void) return ret; #else + giNumActiveThreads --; return Proc_GetCurThread(); #endif } diff --git a/KernelLand/Kernel/time.c b/KernelLand/Kernel/time.c index 2c83fa32..cf3370aa 100644 --- a/KernelLand/Kernel/time.c +++ b/KernelLand/Kernel/time.c @@ -4,13 +4,13 @@ * * Timer Code */ +#define SANITY 1 // Enable ASSERTs +#define DEBUG 0 #include #include #include #include // Proc_GetCurThread - -// === CONSTANTS === -#define NUM_TIMERS 8 +#include // === TYPEDEFS === struct sTimer { @@ -18,82 +18,219 @@ struct sTimer { Sint64 FiresAfter; void (*Callback)(void*); void *Argument; +// tMutex Lock; + BOOL bActive; }; // === PROTOTYPES === +void Timer_CallbackThread(void *Unused); void Timer_CallTimers(void); +#if 0 +tTimer *Time_CreateTimer(int Delta, tTimerCallback *Callback, void *Argument); +void Time_ScheduleTimer(tTimer *Timer, int Delta); +void Time_RemoveTimer(tTimer *Timer); +tTimer *Time_AllocateTimer(tTimerCallback *Callback, void *Argument); +#endif +void Time_InitTimer(tTimer *Timer, tTimerCallback *Callback, void *Argument); +#if 0 +void Time_FreeTimer(tTimer *Timer); +void Time_Delay(int Time); +#endif // === GLOBALS === volatile Uint64 giTicks = 0; volatile Sint64 giTimestamp = 0; volatile Uint64 giPartMiliseconds = 0; -tTimer *gTimers; // TODO: Replace by a ring-list timer +tTimer *gTimers; +tWorkqueue gTimers_CallbackQueue; +tShortSpinlock gTimers_ListLock; // === CODE === +void Timer_CallbackThread(void *Unused) +{ + Threads_SetName("Timer Callback Thread"); + + for(;;) + { + tTimer *timer = Workqueue_GetWork(&gTimers_CallbackQueue); + + if( !timer->Callback ) { + LOG("Timer %p doesn't have a callback", timer); + ASSERT( timer->Callback ); + } + + // Save callback and argument (because once the mutex is released + // the timer may no longer be valid) + tTimerCallback *cb = timer->Callback; + void *arg = timer->Argument; + + LOG("Callback fire %p", timer); + + // Allow Time_RemoveTimer to be called safely + timer->bActive = 0; + + // Fire callback + cb(arg); + + // Mark timer as no longer needed + } +} + /** * \fn void Timer_CallTimers() */ void Timer_CallTimers() { + SHORTLOCK(&gTimers_ListLock); while( gTimers && gTimers->FiresAfter < now() ) { - tTimer *next; + // Get timer from list + tTimer *timer = gTimers; - if( gTimers->Callback ) - gTimers->Callback(gTimers->Argument); - else - Threads_PostEvent(gTimers->Argument, THREAD_EVENT_TIMER); - - next = gTimers->Next; - free(gTimers); - gTimers = next; + ASSERT( gTimers != gTimers->Next ); + gTimers = gTimers->Next; + + // Perform event + if( timer->Callback ) { + LOG("Callback schedule %p", timer); + // PROBLEM! Possibly causes rescheudle during interrupt +// Mutex_Acquire( &timer->Lock ); // Released once the callback fires + Workqueue_AddWork(&gTimers_CallbackQueue, timer); + } + else { + LOG("Event fire %p", timer); + ASSERT( timer->Argument ); + Threads_PostEvent(timer->Argument, THREAD_EVENT_TIMER); + timer->bActive = 0; + } } + SHORTREL(&gTimers_ListLock); } /** - * \brief Schedule an action + * \brief Schedule an action (Legacy) */ tTimer *Time_CreateTimer(int Delta, tTimerCallback *Callback, void *Argument) { - tTimer *ret; + tTimer *ret = malloc(sizeof(tTimer)); + if( !ret ) return NULL; + Time_InitTimer(ret, Callback, Argument); + Time_ScheduleTimer(ret, Delta); + return ret; +} + +/** + * \brief Schedule a timer to fire + */ +void Time_ScheduleTimer(tTimer *Timer, int Delta) +{ tTimer *t, *p; - - if(Callback == NULL) - Argument = Proc_GetCurThread(); - // TODO: Use a pool instead? - ret = malloc(sizeof(tTimer)); + // Sanity checks + if( !Timer ) return ; + + if( Timer->bActive ) return; + + // Set time + Timer->FiresAfter = now() + Delta; - ret->Callback = Callback; - ret->FiresAfter = now() + Delta; - ret->Argument = Argument; + // Debug + LOG("%p added timer %p - %i ms (ts=%lli)", + __builtin_return_address(0), Timer, Delta, Timer->FiresAfter); // Add into list (sorted) + SHORTLOCK(&gTimers_ListLock); +// Mutex_Release( &Timer->Lock ); // Prevent deadlocks for( p = (tTimer*)&gTimers, t = gTimers; t; p = t, t = t->Next ) { - if( t->FiresAfter > ret->FiresAfter ) break; + ASSERT( p != t ); ASSERT( CheckMem(t, sizeof(tTimer)) ); + if( t == Timer ) + { + LOG("Double schedule - increasing delta"); + SHORTREL(&gTimers_ListLock); + return ; + } + LOG(" t = %p ts:%lli", t, t->FiresAfter); + if( t->FiresAfter > Timer->FiresAfter ) break; } - ret->Next = t; - p->Next = ret; - - return ret; + Timer->Next = t; + p->Next = Timer; + Timer->bActive = 1; + LOG(" %p %p %p", p, Timer, t); + SHORTREL(&gTimers_ListLock); } /** - * \brief Delete a timer + * \brief Delete a timer from the running list */ void Time_RemoveTimer(tTimer *Timer) { tTimer *t, *p; + + if( !Timer ) return ; + + SHORTLOCK(&gTimers_ListLock); for( p = (tTimer*)&gTimers, t = gTimers; t; p = t, t = t->Next ) { + ASSERT( p != t ); ASSERT( CheckMem(t, sizeof(tTimer)) ); if( t == Timer ) { p->Next = t->Next; - free(Timer); - return ; + break ; } } + SHORTREL(&gTimers_ListLock); + + if( t ) { + Timer->bActive = 0; + LOG("%p removed %p", __builtin_return_address(0), Timer); + } + else + LOG("%p tried to remove %p (already complete)", __builtin_return_address(0), Timer); +} + +/** + * \brief Allocate a timer object, but don't schedule it + */ +tTimer *Time_AllocateTimer(tTimerCallback *Callback, void *Argument) +{ + tTimer *ret = malloc(sizeof(tTimer)); + if( !ret ) return NULL; + Time_InitTimer(ret, Callback, Argument); + return ret; +} + +/** + * \brief Initialise a timer + * \note Mostly an internal function + */ +void Time_InitTimer(tTimer *Timer, tTimerCallback *Callback, void *Argument) +{ + if(Callback == NULL) + Argument = Proc_GetCurThread(); + Timer->FiresAfter = 0; + Timer->Callback = Callback; + Timer->Argument = Argument; +// memset( &Timer->Lock, 0, sizeof(Timer->Lock) ); + Timer->bActive = 0; +} + +/** + * \brief Free an allocated timer + */ +void Time_FreeTimer(tTimer *Timer) +{ + if( !Timer ) return ; + Time_RemoveTimer( Timer ); // Just in case + + // Ensures that we don't free until the timer callback has started + while( Timer->bActive ) Threads_Yield(); + // Release won't be needed, as nothing should be waiting on it +// Mutex_Acquire( &Timer->Lock ); + + // Free timer + free(Timer); + LOG("%p deallocated %p", __builtin_return_address(0), Timer); } /** @@ -102,13 +239,18 @@ void Time_RemoveTimer(tTimer *Timer) */ void Time_Delay(int Delay) { -// tTime dest = now() + Delay; -// while(dest > now()) Threads_Yield(); - Time_CreateTimer(Delay, NULL, NULL); + tTimer *t; + t = Time_AllocateTimer(NULL, NULL); + Time_ScheduleTimer(t, Delay); Threads_WaitEvents(THREAD_EVENT_TIMER); + Time_FreeTimer(t); } // === EXPORTS === -EXPORT(Time_CreateTimer); +//EXPORT(Time_CreateTimer); +EXPORT(Time_ScheduleTimer); EXPORT(Time_RemoveTimer); +EXPORT(Time_AllocateTimer); +//EXPORT(Time_InitTimer); +EXPORT(Time_FreeTimer); EXPORT(Time_Delay); diff --git a/KernelLand/Kernel/workqueue.c b/KernelLand/Kernel/workqueue.c index b1a63851..9e2c6f6f 100644 --- a/KernelLand/Kernel/workqueue.c +++ b/KernelLand/Kernel/workqueue.c @@ -9,6 +9,8 @@ #include #include +#define QUEUENEXT(ptr) (*( (void**)(ptr) + Queue->NextOffset/sizeof(void*) )) + // === CODE === void Workqueue_Init(tWorkqueue *Queue, const char *Name, size_t NextOfset) { @@ -27,7 +29,7 @@ void *Workqueue_GetWork(tWorkqueue *Queue) if(Queue->Head) { void *ret = Queue->Head; - Queue->Head = *( (void**)ret + Queue->NextOffset/sizeof(void*) ); + Queue->Head = QUEUENEXT( ret ); if(Queue->Tail == ret) Queue->Tail = NULL; SHORTREL(&Queue->Protector); @@ -58,11 +60,12 @@ void Workqueue_AddWork(tWorkqueue *Queue, void *Ptr) SHORTLOCK(&Queue->Protector); if( Queue->Tail ) - *( (void**)Queue->Tail + Queue->NextOffset/sizeof(void*) ) = Ptr; + QUEUENEXT(Queue->Tail) = Ptr; else Queue->Head = Ptr; Queue->Tail = Ptr; - + QUEUENEXT(Ptr) = NULL; + if( Queue->Sleeper ) { if( Queue->Sleeper->Status != THREAD_STAT_ACTIVE ) diff --git a/KernelLand/Modules/Display/VESA/main.c b/KernelLand/Modules/Display/VESA/main.c index a85d3137..c57d57d2 100644 --- a/KernelLand/Modules/Display/VESA/main.c +++ b/KernelLand/Modules/Display/VESA/main.c @@ -12,6 +12,7 @@ #include #include #include "common.h" +#include // === CONSTANTS === #define FLAG_LFB 0x1 @@ -59,7 +60,9 @@ char *gpVesa_Framebuffer = (void*)VESA_DEFAULT_FRAMEBUFFER; // --- Cursor Control --- int giVesaCursorX = -1; int giVesaCursorY = -1; - int giVesaCursorTimer = -1; // Invalid timer +#if BLINKING_CURSOR +tTimer *gpVesaCursorTimer; +#endif int gbVesa_CursorVisible = 0; // --- 2D Video Stream Handlers --- tDrvUtil_Video_BufInfo gVesa_BufInfo; @@ -112,10 +115,15 @@ int Vesa_Install(char **Arguments) // VM8086_Deallocate( info ); + #if BLINKING_CURSOR + // Create blink timer + gpVesaCursorTimer = Time_AllocateTimer( Vesa_FlipCursor, NULL ); + #endif + // Install Device giVesaDriverId = DevFS_AddDevice( &gVesa_DriverStruct ); if(giVesaDriverId == -1) return MODULE_ERR_MISC; - + return MODULE_ERR_OK; } @@ -246,8 +254,7 @@ int Vesa_Int_SetMode(int mode) Vesa_int_FillModeList(); - Time_RemoveTimer(giVesaCursorTimer); - giVesaCursorTimer = -1; + Time_RemoveTimer(gpVesaCursorTimer); Mutex_Acquire( &glVesa_Lock ); @@ -365,9 +372,8 @@ void Vesa_int_HideCursor(void) { DrvUtil_Video_RemoveCursor( &gVesa_BufInfo ); #if BLINKING_CURSOR - if(giVesaCursorTimer != -1) { - Time_RemoveTimer(giVesaCursorTimer); - giVesaCursorTimer = -1; + if(gpVesaCursorTimer) { + Time_RemoveTimer(gpVesaCursorTimer); } #endif } @@ -383,7 +389,7 @@ void Vesa_int_ShowCursor(void) giVesaCursorY*giVT_CharHeight ); #if BLINKING_CURSOR - giVesaCursorTimer = Time_CreateTimer(VESA_CURSOR_PERIOD, Vesa_FlipCursor, NULL); + Time_ScheduleTimer( gpVesaCursorTimer, VESA_CURSOR_PERIOD ); #endif } else @@ -412,7 +418,7 @@ void Vesa_FlipCursor(void *Arg) gbVesa_CursorVisible = !gbVesa_CursorVisible; #if BLINKING_CURSOR - giVesaCursorTimer = Time_CreateTimer(VESA_CURSOR_PERIOD, Vesa_FlipCursor, Arg); + Time_ScheduleTimer( gpVesaCursorTimer, VESA_CURSOR_PERIOD ); #endif } diff --git a/KernelLand/Modules/Storage/FDDv2/fdc.c b/KernelLand/Modules/Storage/FDDv2/fdc.c index e86b31c6..7b9042b9 100644 --- a/KernelLand/Modules/Storage/FDDv2/fdc.c +++ b/KernelLand/Modules/Storage/FDDv2/fdc.c @@ -84,10 +84,17 @@ int FDD_SetupIO(void) // Install IRQ6 Handler IRQ_AddHandler(6, FDD_int_IRQHandler, NULL); + for( int i = 0; i < 2; i ++ ) + { + if( !gaFDD_Disks[i].bValid ) continue ; + + gaFDD_Disks[i].Timer = Time_AllocateTimer(FDD_int_StopMotorCallback, (void*)(tVAddr)i); + } + // Reset controller FDD_int_Reset(0); // TODO: All controllers - + return 0; } @@ -401,7 +408,6 @@ int FDD_int_StartMotor(int Disk) // Clear the motor off timer Time_RemoveTimer(gaFDD_Disks[Disk].Timer); - gaFDD_Disks[Disk].Timer = NULL; // Check if the motor is already on if( gaFDD_Disks[Disk].MotorState == MOTOR_ATSPEED ) @@ -425,10 +431,8 @@ int FDD_int_StopMotor(int Disk) { if( gaFDD_Disks[Disk].MotorState != MOTOR_ATSPEED ) return 0; - if( gaFDD_Disks[Disk].Timer != NULL ) - return 0; - gaFDD_Disks[Disk].Timer = Time_CreateTimer(MOTOR_OFF_DELAY, FDD_int_StopMotorCallback, (void*)(tVAddr)Disk); + Time_ScheduleTimer(gaFDD_Disks[Disk].Timer, MOTOR_OFF_DELAY); return 0; } @@ -443,7 +447,6 @@ void FDD_int_StopMotorCallback(void *Ptr) int _disk; Uint16 base = FDD_int_GetBase(Disk, &_disk); - gaFDD_Disks[Disk].Timer = NULL; gaFDD_Disks[Disk].MotorState = MOTOR_OFF; outb(base + FDC_DOR, inb(base+FDC_DOR) & ~(1 << (_disk + 4))); diff --git a/KernelLand/Modules/USB/Core/hub.c b/KernelLand/Modules/USB/Core/hub.c index 849e8a3f..eccaa3fc 100644 --- a/KernelLand/Modules/USB/Core/hub.c +++ b/KernelLand/Modules/USB/Core/hub.c @@ -7,6 +7,7 @@ */ #define DEBUG 1 #include +#include #define MAX_PORTS 32 // Not actually a max, but used for DeviceRemovable diff --git a/KernelLand/Modules/USB/UHCI/uhci.c b/KernelLand/Modules/USB/UHCI/uhci.c index 3b2c6590..8477c8f7 100644 --- a/KernelLand/Modules/USB/UHCI/uhci.c +++ b/KernelLand/Modules/USB/UHCI/uhci.c @@ -12,6 +12,7 @@ #include #include #include "uhci.h" +#include // === CONSTANTS === #define MAX_CONTROLLERS 4