size_t VT_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);
size_t VT_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer);
int VT_Terminal_IOCtl(tVFS_Node *Node, int Id, void *Data);
+void VT_Terminal_Reference(tVFS_Node *Node);
+void VT_Terminal_Close(tVFS_Node *Node);
+//void VT_SetTerminal(int Term);
// === CONSTANTS ===
VT_InitOutput();
VT_InitInput();
+
// Create Nodes
+ Log_Debug("VTerm", "Initialising nodes (and creating buffers)");
for( i = 0; i < NUM_VTS; i++ )
{
gVT_Terminals[i].Mode = TERM_MODE_TEXT;
// Semaphore_Init(&gVT_Terminals[i].InputSemaphore, 0, MAX_INPUT_CHARS8, "VTerm", gVT_Terminals[i].Name);
}
+ Log_Debug("VTerm", "Registering with DevFS");
// Add to DevFS
DevFS_AddDevice( &gVT_DrvInfo );
// Set kernel output to VT0
+ Log_Debug("VTerm", "Setting kernel output to VT#0");
Debug_SetKTerminal("/Devices/VTerm/0");
return MODULE_ERR_OK;
return -1;
}
+void VT_Terminal_Reference(tVFS_Node *Node)
+{
+ // Append PID to list
+}
+
+void VT_Terminal_Close(tVFS_Node *Node)
+{
+ // Remove PID from list
+}
+
/**
* \fn void VT_SetTerminal(int ID)
* \brief Set the current terminal
Uint32 RawScancode; //!< last raw scancode recieved
// tSemaphore InputSemaphore;
+ tPGID OwningProcessGroup; //!< The process group that owns the terminal
+
Uint32 *Buffer;
// TODO: Do I need to keep this about?
*/
#include "vterm.h"
#include <api_drv_keyboard.h>
+#define DEBUG 1
// === GLOBALS ===
// --- Key States --- (Used for VT Switching/Magic Combos)
return ;
}
VFS_IOCtl(giVT_InputDevHandle, KB_IOCTL_SETCALLBACK, VT_KBCallBack);
+ LOG("VTerm input initialised");
}
/**
break;
case KEYSYM_HOME:
- case KEYSYM_KP7:
+ case KEYSYM_KP7: // Codepoint==0, then it's home (not translated)
buf[0] = '\x1B'; buf[1] = 'O'; buf[2] = 'H';
len = 3;
break;
case KEYSYM_END:
- case KEYSYM_KP1:
+ case KEYSYM_KP1: // You get the drill
buf[0] = '\x1B'; buf[1] = 'O'; buf[2] = 'F';
len = 3;
break;
case KEYSYM_INSERT:
- case KEYSYM_KP0:
+ case KEYSYM_KP0: // See above
buf[0] = '\x1B'; buf[1] = '['; buf[2] = '2'; buf[3] = '~';
len = 4;
break;
case KEYSYM_DELETE:
- case KEYSYM_KPPERIOD:
+ case KEYSYM_KPPERIOD: // Are you that dumb? Look up
buf[0] = '\x1B'; buf[1] = '['; buf[2] = '3'; buf[3] = '~';
len = 4;
break;
}
}
+ else if( gbVT_CtrlDown )
+ {
+ len = 1;
+ switch( term->RawScancode )
+ {
+ case KEYSYM_2:
+ buf[0] = '\0';
+ break;
+ case KEYSYM_3 ... KEYSYM_7:
+ buf[0] = 0x1b + (term->RawScancode - KEYSYM_3);
+ break;
+ case KEYSYM_8:
+ buf[0] = 0x7f;
+ break;
+ // - Ctrl-A = \1, Ctrl-Z = \x1a
+ case KEYSYM_a ... KEYSYM_z:
+ buf[0] = 0x01 + (term->RawScancode - KEYSYM_a);
+ break;
+ default:
+ goto utf_encode;
+ }
+ }
else
{
+ utf_encode:
// Attempt to encode in UTF-8
len = WriteUTF8( buf, Codepoint );
if(len == 0) {
// Handle meta characters
if( !(term->Flags & VT_FLAG_RAWIN) )
{
+ // Implementation options for Ctrl-C -> SIGINT
+ // - Kernel-land: here in the VT
+ // > Pros: No userland change needed
+ // > Cons: Requires process groups
+ // - User-land, in the shell
+ // > Pros: Less threading changes
+ // > Cons: Needs the shell to get all user input before the app, worse latency
+ // > Won't work with bash etc
switch(buf[0])
{
case '\3': // ^C
#endif
// Write
- if( MAX_INPUT_CHARS8 - term->InputWrite >= len )
+ if( MAX_INPUT_CHARS8 - term->InputWrite >= len ) {
memcpy( &term->InputBuffer[term->InputWrite], buf, len );
+ }
else {
memcpy( &term->InputBuffer[term->InputWrite], buf, MAX_INPUT_CHARS8 - term->InputWrite );
memcpy( &term->InputBuffer[0], buf, len - (MAX_INPUT_CHARS8 - term->InputWrite) );
*/
#include "vterm.h"
#include <api_drv_video.h>
+#define DEBUG 1
// === CODE ===
/**
VT_SetResolution( giVT_RealWidth, giVT_RealHeight );
VT_SetTerminal( 0 );
VT_SetMode( VIDEO_BUFFMT_TEXT );
+ LOG("VTerm output initialised");
}
/**
// --- Types ---
typedef Uint32 tPID; //!< Process ID type
+typedef Uint32 tPGID; //!< Process Group ID type
typedef Uint32 tTID; //!< Thread ID Type
typedef Uint32 tUID; //!< User ID Type
typedef Uint32 tGID; //!< Group ID Type
#define CLONE_VM 0x10
//! Don't copy user pages
#define CLONE_NOUSER 0x20
+//! Inherit the parent's PGID
+#define CLONE_PGID 0x40
/**
* \}
*/
#include <threads.h>
#include <proc.h>
-
typedef struct sProcess tProcess;
/**
*/
struct sProcess
{
+ struct sProcess *Next;
+ tPGID PGID;
tPID PID;
+
int nThreads;
+ struct sThread *FirstThread;
tUID UID; //!< User ID
tGID GID; //!< User and Group
struct sThread *Next;
struct sThread *GlobalNext; //!< Next thread in global list
struct sThread *GlobalPrev; //!< Previous thread in global list
+ struct sThread *ProcessNext;
tShortSpinlock IsLocked; //!< Thread's spinlock
volatile int Status; //!< Thread Status
void *WaitPointer; //!< What (Mutex/Thread/other) is the thread waiting on
new->Process = malloc( sizeof(struct sProcess) );
newproc = new->Process;
newproc->PID = new->TID;
+ if( Flags & CLONE_PGID )
+ newproc->PGID = oldproc->PGID;
+ else
+ newproc->PGID = newproc->PID;
newproc->UID = oldproc->UID;
newproc->GID = oldproc->GID;
newproc->MaxFD = oldproc->MaxFD;
}
// --- Process Structure Access Functions ---
+tPGID Threads_GetPGID(void)
+{
+ return Proc_GetCurThread()->Process->PGID;
+}
tPID Threads_GetPID(void)
{
return Proc_GetCurThread()->Process->PID;