// === PROTOTYPES ===
int VT_Install(char **Arguments);
-char *VT_ReadDir(tVFS_Node *Node, int Pos);
-tVFS_Node *VT_FindDir(tVFS_Node *Node, const char *Name);
int VT_Root_IOCtl(tVFS_Node *Node, int Id, void *Data);
-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);
+void VT_int_PutFBData(tVTerm *Term, size_t Offset, size_t Length, const void *Data);
+void VT_PTYOutput(void *Handle, size_t Length, const void *Data);
+ int VT_PTYResize(void *Handle, const struct ptydims *Dims);
+ int VT_PTYModeset(void *Handle, const struct ptymode *Mode);
// === CONSTANTS ===
// === GLOBALS ===
-MODULE_DEFINE(0, VERSION, VTerm, VT_Install, NULL, NULL);
+MODULE_DEFINE(0, VERSION, VTerm, VT_Install, NULL, "PTY", NULL);
tVFS_NodeType gVT_RootNodeType = {
.TypeName = "VTerm Root",
- .ReadDir = VT_ReadDir,
- .FindDir = VT_FindDir,
.IOCtl = VT_Root_IOCtl
};
-tVFS_NodeType gVT_TermNodeType = {
- .TypeName = "VTerm",
- .Read = VT_Read,
- .Write = VT_Write,
- .IOCtl = VT_Terminal_IOCtl
- };
tDevFS_Driver gVT_DrvInfo = {
NULL, "VTerm",
{
- .Flags = VFS_FFLAG_DIRECTORY,
+ .Flags = 0,
.Size = NUM_VTS,
.Inode = -1,
.NumACLs = 0,
if( strcmp(opt, "Video") == 0 ) {
if( !gsVT_OutputDevice )
- gsVT_OutputDevice = strdup(val);
+ gsVT_OutputDevice = val;
}
else if( strcmp(opt, "Input") == 0 ) {
if( !gsVT_InputDevice )
- gsVT_InputDevice = strdup(val);
+ gsVT_InputDevice = val;
}
else if( strcmp(opt, "Width") == 0 ) {
giVT_RealWidth = atoi( val );
else if( strcmp(opt, "Scrollback") == 0 ) {
giVT_Scrollback = atoi( val );
}
+ else {
+ Log_Notice("VTerm", "Unknown option '%s'", opt);
+ }
}
}
gVT_Terminals[i].WritePos = 0;
gVT_Terminals[i].AltWritePos = 0;
gVT_Terminals[i].ViewPos = 0;
- gVT_Terminals[i].ReadingThread = -1;
gVT_Terminals[i].ScrollHeight = 0;
// Initialise
- VT_int_ChangeMode( &gVT_Terminals[i],
- TERM_MODE_TEXT, giVT_RealWidth, giVT_RealHeight );
-
- gVT_Terminals[i].Name[0] = '0'+i;
- gVT_Terminals[i].Name[1] = '\0';
- gVT_Terminals[i].Node.Inode = i;
- gVT_Terminals[i].Node.ImplPtr = &gVT_Terminals[i];
- gVT_Terminals[i].Node.NumACLs = 0; // Only root can open virtual terminals
-
- gVT_Terminals[i].Node.Type = &gVT_TermNodeType;
-// Semaphore_Init(&gVT_Terminals[i].InputSemaphore, 0, MAX_INPUT_CHARS8, "VTerm", gVT_Terminals[i].Name);
+ VT_int_Resize( &gVT_Terminals[i], giVT_RealWidth, giVT_RealHeight );
+ gVT_Terminals[i].Mode = PTYBUFFMT_TEXT;
+ char name[] = {'v','t','0'+i,'\0'};
+ gVT_Terminals[i].PTY = PTY_Create(name, &gVT_Terminals[i],
+ VT_PTYOutput, VT_PTYResize, VT_PTYModeset);
+ struct ptymode mode = {
+ .OutputMode = PTYBUFFMT_TEXT,
+ .InputMode = PTYIMODE_CANON|PTYIMODE_ECHO
+ };
+ PTY_SetAttrib(gVT_Terminals[i].PTY, NULL, &mode, 0);
}
- 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");
+ Debug_SetKTerminal("/Devices/pts/vt0c");
return MODULE_ERR_OK;
}
VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_GETSETMODE, &tmp );
// Resize text terminals if needed
+ // - VT0 check is for the first resolution set
if( gVT_Terminals[0].Text && (giVT_RealWidth != mode.width || giVT_RealHeight != mode.height) )
{
int newBufSize = (giVT_RealWidth/giVT_CharWidth)
}
}
-/**
- * \fn char *VT_ReadDir(tVFS_Node *Node, int Pos)
- * \brief Read from the VTerm Directory
- */
-char *VT_ReadDir(tVFS_Node *Node, int Pos)
-{
- if(Pos < 0) return NULL;
- if(Pos >= NUM_VTS) return NULL;
- return strdup( gVT_Terminals[Pos].Name );
-}
-
-/**
- * \fn tVFS_Node *VT_FindDir(tVFS_Node *Node, const char *Name)
- * \brief Find an item in the VTerm directory
- * \param Node Root node
- * \param Name Name (number) of the terminal
- */
-tVFS_Node *VT_FindDir(tVFS_Node *Node, const char *Name)
-{
- int num;
-
- ENTER("pNode sName", Node, Name);
-
- // Open the input and output files if needed
- if(giVT_OutputDevHandle == -2) VT_InitOutput();
- if(giVT_InputDevHandle == -2) VT_InitInput();
-
- // Sanity check name
- if(Name[0] < '0' || Name[0] > '9' || Name[1] != '\0') {
- LEAVE('n');
- return NULL;
- }
- // Get index
- num = Name[0] - '0';
- if(num >= NUM_VTS) {
- LEAVE('n');
- return NULL;
- }
- // Return node
- LEAVE('p', &gVT_Terminals[num].Node);
- return &gVT_Terminals[num].Node;
-}
-
/**
* \fn int VT_Root_IOCtl(tVFS_Node *Node, int Id, void *Data)
* \brief Control the VTerm Driver
return 0;
}
-/**
- * \brief Read from a virtual terminal
- */
-size_t VT_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
+void VT_int_PutFBData(tVTerm *Term, size_t Offset, size_t Length, const void *Buffer)
{
- int pos = 0;
- int avail;
- tVTerm *term = &gVT_Terminals[ Node->Inode ];
- Uint32 *codepoint_buf = Buffer;
- Uint32 *codepoint_in;
-
- Mutex_Acquire( &term->ReadingLock );
+ size_t maxlen = Term->Width * Term->Height * 4;
+
+ if( Offset >= maxlen )
+ return ;
+
+ Length = MIN(Length, maxlen - Offset);
- // Check current mode
- switch(term->Mode)
+ // If the terminal is currently shown, write directly to the screen
+ if( Term == gpVT_CurTerm )
{
- // Text Mode (UTF-8)
- case TERM_MODE_TEXT:
- VT_int_UpdateCursor(term, 1);
-
- VFS_SelectNode(Node, VFS_SELECT_READ, NULL, "VT_Read (UTF-8)");
-
- avail = term->InputWrite - term->InputRead;
- if(avail < 0)
- avail += MAX_INPUT_CHARS8;
- if(avail > Length - pos)
- avail = Length - pos;
+ // Center the terminal vertically
+ if( giVT_RealHeight > Term->Height )
+ Offset += (giVT_RealHeight - Term->Height) / 2 * Term->Width * 4;
- while( avail -- )
+ // If the terminal is not native width, center it horizontally
+ if( giVT_RealWidth > Term->Width )
{
- ((char*)Buffer)[pos] = term->InputBuffer[term->InputRead];
- pos ++;
- term->InputRead ++;
- while(term->InputRead >= MAX_INPUT_CHARS8)
- term->InputRead -= MAX_INPUT_CHARS8;
+ // No? :( Well, just center it
+ int x, y, w, h;
+ Uint dst_ofs;
+ // TODO: Fix to handle the final line correctly?
+ x = Offset/4; y = x / Term->Width; x %= Term->Width;
+ w = Length/4+x; h = w / Term->Width; w %= Term->Width;
+
+ // Center
+ x += (giVT_RealWidth - Term->Width) / 2;
+ dst_ofs = (x + y * giVT_RealWidth) * 4;
+ while(h--)
+ {
+ VFS_WriteAt( giVT_OutputDevHandle,
+ dst_ofs,
+ Term->Width * 4,
+ Buffer
+ );
+ Buffer = (const Uint32*)Buffer + Term->Width;
+ dst_ofs += giVT_RealWidth * 4;
+ }
}
- break;
-
- //case TERM_MODE_FB:
- // Other - UCS-4
- default:
- VFS_SelectNode(Node, VFS_SELECT_READ, NULL, "VT_Read (UCS-4)");
-
- avail = term->InputWrite - term->InputRead;
- if(avail < 0)
- avail += MAX_INPUT_CHARS32;
- Length /= 4;
- if(avail > Length - pos)
- avail = Length - pos;
-
- codepoint_in = (void*)term->InputBuffer;
- codepoint_buf = Buffer;
-
- while( avail -- )
+ // otherwise, just go directly to the screen
+ else
{
- codepoint_buf[pos] = codepoint_in[term->InputRead];
- pos ++;
- term->InputRead ++;
- while(term->InputRead >= MAX_INPUT_CHARS32)
- term->InputRead -= MAX_INPUT_CHARS32;
+ VFS_WriteAt( giVT_OutputDevHandle, Offset, Length, Buffer );
}
- pos *= 4;
- break;
}
-
- // Mark none avaliable if buffer empty
- if( term->InputRead == term->InputWrite )
- VFS_MarkAvaliable(&term->Node, 0);
-
- term->ReadingThread = -1;
-
-// VT_int_UpdateCursor(term, term->Mode == TERM_MODE_TEXT);
-
- Mutex_Release( &term->ReadingLock );
-
- return pos;
+ // If not active, write to the backbuffer (allocating if needed)
+ else
+ {
+ if( !Term->Buffer )
+ Term->Buffer = malloc( Term->Width * Term->Height * 4 );
+ // Copy to the local cache
+ memcpy( (char*)Term->Buffer + Offset, Buffer, Length );
+ }
}
-/**
- * \brief Write to a virtual terminal
- */
-size_t VT_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer)
+void VT_PTYOutput(void *Handle, size_t Length, const void *Data)
{
- tVTerm *term = &gVT_Terminals[ Node->Inode ];
- int size;
-
- // Write
+ tVTerm *term = Handle;
switch( term->Mode )
{
- // Print Text
- case TERM_MODE_TEXT:
- VT_int_PutString(term, Buffer, Length);
+ case PTYBUFFMT_TEXT:
+ VT_int_PutString(term, Data, Length);
break;
-
- // Framebuffer :)
- case TERM_MODE_FB:
- // - Sanity Checking
- size = term->Width*term->Height*4;
- if( Offset > size ) {
- Log_Notice("VTerm", "VT_Write: Offset (0x%llx) > FBSize (0x%x)",
- Offset, size);
- return 0;
- }
- if( Offset + Length > size ) {
- Log_Notice("VTerm", "VT_Write: Offset+Length (0x%llx) > FBSize (0x%x)",
- Offset+Length, size);
- Length = size - Offset;
- }
-
- // Update screen if needed
- if( Node->Inode == giVT_CurrentTerminal )
- {
- if( giVT_RealHeight > term->Height )
- Offset += (giVT_RealHeight - term->Height) / 2 * term->Width * 4;
- // Handle undersized virtual terminals
- if( giVT_RealWidth > term->Width )
- {
- // No? :( Well, just center it
- int x, y, w, h;
- Uint dst_ofs;
- // TODO: Fix to handle the final line correctly?
- x = Offset/4; y = x / term->Width; x %= term->Width;
- w = Length/4+x; h = w / term->Width; w %= term->Width;
-
- // Center
- x += (giVT_RealWidth - term->Width) / 2;
- dst_ofs = (x + y * giVT_RealWidth) * 4;
- while(h--)
- {
- VFS_WriteAt( giVT_OutputDevHandle,
- dst_ofs,
- term->Width * 4,
- Buffer
- );
- Buffer = (void*)( (Uint)Buffer + term->Width*4 );
- dst_ofs += giVT_RealWidth * 4;
- }
- return 0;
- }
- else
- {
- return VFS_WriteAt( giVT_OutputDevHandle, Offset, Length, Buffer );
- }
- }
- else
- {
- if( !term->Buffer )
- term->Buffer = malloc( term->Width * term->Height * 4 );
- // Copy to the local cache
- memcpy( (char*)term->Buffer + (Uint)Offset, Buffer, Length );
- }
+ case PTYBUFFMT_FB:
+ // TODO: How do offset?
+ VT_int_PutFBData(term, 0, Length, Data);
break;
- // Just pass on (for now)
- // TODO: Handle locally too to ensure no information is lost on
- // VT Switch (and to isolate terminals from each other)
- case TERM_MODE_2DACCEL:
- //case TERM_MODE_3DACCEL:
- if( Node->Inode == giVT_CurrentTerminal )
- {
- VFS_Write( giVT_OutputDevHandle, Length, Buffer );
- }
+ case PTYBUFFMT_2DCMD:
+ // TODO: Impliment 2D commands
+ break;
+ case PTYBUFFMT_3DCMD:
+ // TODO: Impliment 3D commands
break;
}
-
+}
+
+int VT_PTYResize(void *Handle, const struct ptydims *Dims)
+{
+ tVTerm *term = Handle;
+ int newW = Dims->W * (term->Mode == PTYBUFFMT_TEXT ? giVT_CharWidth : 1);
+ int newH = Dims->H * (term->Mode == PTYBUFFMT_TEXT ? giVT_CharHeight : 1);
+ if( newW > giVT_RealWidth || newH > giVT_RealHeight )
+ return 1;
+ VT_int_Resize(term, newW, newH);
+ return 0;
+}
+
+int VT_PTYModeset(void *Handle, const struct ptymode *Mode)
+{
+ tVTerm *term = Handle;
+ term->Mode = (Mode->OutputMode & PTYOMODE_BUFFMT);
return 0;
}
+#if 0
/**
* \fn int VT_Terminal_IOCtl(tVFS_Node *Node, int Id, void *Data)
* \brief Call an IO Control on a virtual terminal
{
// Remove PID from list
}
+#endif
/**
* \fn void VT_SetTerminal(int ID)
gpVT_CurTerm->Buffer = malloc( gpVT_CurTerm->Width*gpVT_CurTerm->Height*4 );
if( gpVT_CurTerm->Width < giVT_RealWidth )
{
- int line;
Uint ofs = 0;
Uint32 *dest = gpVT_CurTerm->Buffer;
// Slower scanline copy
- for( line = 0; line < gpVT_CurTerm->Height; line ++ )
+ for( int line = 0; line < gpVT_CurTerm->Height; line ++ )
{
VFS_ReadAt(giVT_OutputDevHandle, ofs, gpVT_CurTerm->Width*4, dest);
ofs += giVT_RealWidth * 4;
gpVT_CurTerm->Buffer
);
}
+ LOG("Cached screen contents");
}
// Update current terminal ID