diff --git a/Kernel/include/acess.h b/Kernel/include/acess.h
index a27ebd61bfcbadcf69cfb9be2a9b64aa93535cf9..1f969f8a2b128b3cce21285d2ce00a720b1d8373 100644
--- a/Kernel/include/acess.h
+++ b/Kernel/include/acess.h
@@ -22,14 +22,24 @@ typedef Uint	tGID;
 typedef Sint64	tTimestamp;
 typedef struct sShortSpinlock	tShortSpinlock;
 typedef struct sMutex	tMutex;
+typedef struct sSemaphore	tSemaphore;
 
 struct sMutex {
 	tShortSpinlock	Protector;	//!< Protector for the lock strucure
+	const char	*Name;	//!< Human-readable name
 	struct sThread	*volatile Owner;	//!< Owner of the lock (set upon getting the lock)
 	struct sThread	*Waiting;	//!< Waiting threads
 	struct sThread	*LastWaiting;	//!< Waiting threads
 };
 
+struct sSemaphore {
+	tShortSpinlock	Protector;	//!< Protector for the lock strucure
+	const char	*Name;	//!< Human-readable name
+	volatile int	Value;	//!< Current mutex value
+	struct sThread	*Waiting;	//!< Waiting threads
+	struct sThread	*LastWaiting;	//!< Waiting threads
+};
+
 // --- Helper Macros ---
 /**
  * \name Helper Macros
diff --git a/Kernel/include/threads.h b/Kernel/include/threads.h
index 2b8f9fba3785164a63a765705d7dcafae2a0dc4c..6fbc11fcd58643d28fa5dd2f51df73544f78285d 100644
--- a/Kernel/include/threads.h
+++ b/Kernel/include/threads.h
@@ -74,6 +74,7 @@ enum {
 	THREAD_STAT_ACTIVE,	// Running and schedulable process
 	THREAD_STAT_SLEEPING,	// Message Sleep
 	THREAD_STAT_MUTEXSLEEP,	// Mutex Sleep
+	THREAD_STAT_SEMAPHORESLEEP,	// Semaphore Sleep
 	THREAD_STAT_WAITING,	// ??? (Waiting for a thread)
 	THREAD_STAT_PREINIT,	// Being created
 	THREAD_STAT_ZOMBIE,	// Died/Killed, but parent not informed
diff --git a/Kernel/threads.c b/Kernel/threads.c
index 73c3f3c08b649d10d62c504a17ce2de0f8ea7dcc..87001540d9a925108438f304a61ac81d654c3a61 100644
--- a/Kernel/threads.c
+++ b/Kernel/threads.c
@@ -62,6 +62,7 @@ tGID	Threads_GetGID(void);
  int	Threads_SetGID(Uint *Errno, tUID ID);
 void	Threads_Dump(void);
 void	Threads_DumpActive(void);
+
 void	Mutex_Acquire(tMutex *Mutex);
 void	Mutex_Release(tMutex *Mutex);
  int	Mutex_IsLocked(tMutex *Mutex);
@@ -1227,6 +1228,86 @@ int Mutex_IsLocked(tMutex *Mutex)
 	return Mutex->Owner != NULL;
 }
 
+/**
+ * \brief Initialise the semaphore
+ * \param Value	Initial value of the semaphore
+ * \param Label	Symbolic name
+ */
+void Semaphore_Init(tSemaphore *Sem, int Value, const char *Label)
+{
+	Sem->Value = Value;
+	Sem->Name = Label;
+}
+
+/**
+ * \brief Acquire a "item" from the semaphore
+ */
+void Semaphore_Wait(tSemaphore *Sem)
+{
+	tThread	*us;
+	
+	SHORTLOCK( &Sem->Protector );
+	if( Sem->Value > 0 ) {
+		Sem->Value --;
+		SHORTREL( &Sem->Protector );
+		return ;
+	}
+	
+	SHORTLOCK( &glThreadListLock );
+	
+	// - Remove from active list
+	us = Threads_RemActive();
+	us->Next = NULL;
+	// - Mark as sleeping
+	us->Status = THREAD_STAT_SEMAPHORESLEEP;
+	us->WaitPointer = Sem;
+	
+	// - Add to waiting
+	if(Sem->LastWaiting) {
+		Sem->LastWaiting->Next = us;
+		Sem->LastWaiting = us;
+	}
+	else {
+		Sem->Waiting = us;
+		Sem->LastWaiting = us;
+	}
+	
+	SHORTREL( &glThreadListLock );
+	SHORTREL( &Sem->Protector );
+	while(us->Status == THREAD_STAT_MUTEXSLEEP)	Threads_Yield();
+	// We're only woken when there's something avaliable
+	us->WaitPointer = NULL;
+}
+
+/**
+ * \brief Add an "item" to the semaphore
+ */
+void Semaphore_Signal(tSemaphore *Sem)
+{
+	SHORTLOCK( &Sem->Protector );
+	Sem->Value ++;
+	
+	if( Sem->Waiting )
+	{
+		tThread	*toWake = Sem->Waiting;
+		
+		Sem->Waiting = Sem->Waiting->Next;	// Next!
+		// Reset ->LastWaiting to NULL if we have just removed the last waiting thread
+		if( Sem->Waiting == NULL )
+			Sem->LastWaiting = NULL;
+		
+		// Wake new owner
+		SHORTLOCK( &glThreadListLock );
+		if( toWake->Status != THREAD_STAT_ACTIVE )
+			Threads_AddActive(toWake);
+		SHORTREL( &glThreadListLock );
+		
+		// Decrement (the value is now "owned" by `toWake`)
+		Sem->Value --;
+	}
+	SHORTREL( &Sem->Protector );
+}
+
 // === EXPORTS ===
 EXPORT(Threads_GetUID);
 EXPORT(Threads_GetGID);
diff --git a/Modules/Display/VESA/main.c b/Modules/Display/VESA/main.c
index 425533bdb280ae434d9723ab1c5b38fcc4f68640..479be3028d905fb3da2a511145d18986b4116dbb 100644
--- a/Modules/Display/VESA/main.c
+++ b/Modules/Display/VESA/main.c
@@ -2,7 +2,7 @@
  * AcessOS 1
  * Video BIOS Extensions (Vesa) Driver
  */
-#define DEBUG	0
+#define DEBUG	1
 #define VERSION	0x100
 
 #include <acess.h>
@@ -93,13 +93,15 @@ int Vesa_Install(char **Arguments)
 		return MODULE_ERR_NOTNEEDED;
 	}
 	
-	Log_Debug("VESA", "info->VideoModes = %04x:%04x", info->VideoModes.seg, info->VideoModes.ofs);
+	//Log_Debug("VESA", "info->VideoModes = %04x:%04x", info->VideoModes.seg, info->VideoModes.ofs);
 	modes = (Uint16 *) VM8086_GetPointer(gpVesa_BiosState, info->VideoModes.seg, info->VideoModes.ofs);
 	
 	// Read Modes
 	for( giVesaModeCount = 0; modes[giVesaModeCount] != 0xFFFF; giVesaModeCount++ );
 	gVesa_Modes = (tVesa_Mode *)malloc( giVesaModeCount * sizeof(tVesa_Mode) );
 	
+	Log_Debug("VESA", "%i Modes", giVesaModeCount);
+	
 	// Insert Text Mode
 	gVesa_Modes[0].width = 80;
 	gVesa_Modes[0].height = 25;
diff --git a/Modules/Network/NE2000/ne2000.c b/Modules/Network/NE2000/ne2000.c
index d5eadb778b7913478011268b5f23735aad5b56e4..d75258027e8e907d670771da8df0a82f5ef05b5d 100644
--- a/Modules/Network/NE2000/ne2000.c
+++ b/Modules/Network/NE2000/ne2000.c
@@ -252,7 +252,6 @@ static const char *casIOCtls[] = { DRV_IOCTLNAMES, DRV_NETWORK_IOCTLNAMES, NULL
  */
 int Ne2k_IOCtl(tVFS_Node *Node, int ID, void *Data)
 {
-	 int	tmp;
 	ENTER("pNode iID pData", Node, ID, Data);
 	switch( ID )
 	{