X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=KernelLand%2FKernel%2Fdrv%2Fvterm.c;h=2c6a0d2f8a79ce34cda825b1f8fc3a21250ed2be;hb=56f9364724d8d04a8ffb6dec4213a5ae86968686;hp=fc6dea26487e2d95e897f05225349f15193581f2;hpb=4ebe00546574e97c5316881881f7f2562deea74b;p=tpg%2Facess2.git diff --git a/KernelLand/Kernel/drv/vterm.c b/KernelLand/Kernel/drv/vterm.c index fc6dea26..2c6a0d2f 100644 --- a/KernelLand/Kernel/drv/vterm.c +++ b/KernelLand/Kernel/drv/vterm.c @@ -5,7 +5,7 @@ * drv/vterm.c * - Virtual Terminal - Initialisation and VFS Interface */ -#define DEBUG 0 +#define DEBUG 1 #include "vterm.h" #include #include @@ -20,7 +20,6 @@ #define NUM_VTS 8 //#define DEFAULT_OUTPUT "BochsGA" #define DEFAULT_OUTPUT "Vesa" -#define FALLBACK_OUTPUT "x86_VGAText" #define DEFAULT_INPUT "Keyboard" #define DEFAULT_WIDTH 640 #define DEFAULT_HEIGHT 480 @@ -34,36 +33,24 @@ extern void Debug_SetKTerminal(const char *File); // === PROTOTYPES === int VT_Install(char **Arguments); - int VT_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]); -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, @@ -110,15 +97,15 @@ int VT_Install(char **Arguments) data[ val - arg ] = '\0'; val ++; } - Log_Debug("VTerm", "Argument '%s'", arg); + Log_Debug("VTerm", "Argument '%s'='%s'", opt, val); 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 ); @@ -129,15 +116,18 @@ int VT_Install(char **Arguments) else if( strcmp(opt, "Scrollback") == 0 ) { giVT_Scrollback = atoi( val ); } + else { + Log_Notice("VTerm", "Unknown option '%s'", opt); + } } } // Apply Defaults if(!gsVT_OutputDevice) gsVT_OutputDevice = (char*)DEFAULT_OUTPUT; else if( Module_EnsureLoaded( gsVT_OutputDevice ) ) gsVT_OutputDevice = (char*)DEFAULT_OUTPUT; - if( Module_EnsureLoaded( gsVT_OutputDevice ) ) gsVT_OutputDevice = (char*)FALLBACK_OUTPUT; + //if( Module_EnsureLoaded( gsVT_OutputDevice ) ) gsVT_OutputDevice = (char*)FALLBACK_OUTPUT; if( Module_EnsureLoaded( gsVT_OutputDevice ) ) { - Log_Error("VTerm", "Fallback video '%s' is not avaliable, giving up", FALLBACK_OUTPUT); + Log_Error("VTerm", "Video device '%s' is not avaliable, giving up", gsVT_OutputDevice); return MODULE_ERR_MISC; } @@ -172,28 +162,26 @@ int VT_Install(char **Arguments) Log_Debug("VTerm", "Initialising nodes (and creating buffers)"); for( i = 0; i < NUM_VTS; i++ ) { - gVT_Terminals[i].Mode = TERM_MODE_TEXT; - gVT_Terminals[i].Flags = 0; // gVT_Terminals[i].Flags = VT_FLAG_HIDECSR; //HACK - Stop all those memcpy calls gVT_Terminals[i].CurColour = DEFAULT_COLOUR; - 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; + gVT_Terminals[i].Mode = PTYBUFFMT_TEXT; // 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 ); + char name[] = {'v','t','0'+i,'\0'}; + struct ptydims dims = { + .W = giVT_RealWidth / giVT_CharWidth, + .H = giVT_RealHeight / giVT_CharHeight, + .PW = giVT_RealWidth, + .PH = giVT_RealHeight + }; + struct ptymode mode = { + .OutputMode = PTYBUFFMT_TEXT, + .InputMode = PTYIMODE_CANON|PTYIMODE_ECHO + }; + gVT_Terminals[i].PTY = PTY_Create(name, &gVT_Terminals[i], + VT_PTYOutput, VT_PTYResize, VT_PTYModeset, + &dims, &mode); } // Add to DevFS @@ -201,7 +189,7 @@ int VT_Install(char **Arguments) // Set kernel output to VT0 Log_Debug("VTerm", "Setting kernel output to VT#0"); - Debug_SetKTerminal("/Devices/VTerm/0"); + Debug_SetKTerminal("/Devices/pts/vt0"); return MODULE_ERR_OK; } @@ -239,6 +227,7 @@ void VT_SetResolution(int Width, int Height) 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) @@ -264,50 +253,6 @@ void VT_SetResolution(int Width, int Height) } } -/** - * \fn char *VT_ReadDir(tVFS_Node *Node, int Pos) - * \brief Read from the VTerm Directory - */ -int VT_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]) -{ - if(Pos < 0) return -EINVAL; - if(Pos >= NUM_VTS) return -EINVAL; - strncpy(Dest, gVT_Terminals[Pos].Name, FILENAME_MAX); - return 0; -} - -/** - * \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 @@ -348,174 +293,129 @@ int VT_Root_IOCtl(tVFS_Node *Node, int Id, void *Data) 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, avail; - tVTerm *term = &gVT_Terminals[ Node->Inode ]; - Uint32 *codepoint_buf = Buffer; - Uint32 *codepoint_in; - - Mutex_Acquire( &term->ReadingLock ); - - // Check current mode - switch(term->Mode) - { - // 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) - avail = Length; - - pos = 0; - while( avail -- ) - { - ((char*)Buffer)[pos] = term->InputBuffer[term->InputRead]; - pos ++; - term->InputRead ++; - while(term->InputRead >= MAX_INPUT_CHARS8) - term->InputRead -= MAX_INPUT_CHARS8; - } - 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) - avail = Length; - - codepoint_in = (void*)term->InputBuffer; - codepoint_buf = Buffer; - - pos = 0; - while( avail -- ) - { - codepoint_buf[pos] = codepoint_in[term->InputRead]; - pos ++; - term->InputRead ++; - while(term->InputRead >= MAX_INPUT_CHARS32) - term->InputRead -= MAX_INPUT_CHARS32; - } - pos *= 4; - break; - } - - // Mark none avaliable if buffer empty - if( term->InputRead == term->InputWrite ) - VFS_MarkAvaliable(&term->Node, 0); - - term->ReadingThread = -1; + size_t maxlen = Term->Width * Term->Height * 4; -// VT_int_UpdateCursor(term, term->Mode == TERM_MODE_TEXT); + ENTER("pTerm xOffset xLength pBuffer", Term, Offset, Length, Buffer); - Mutex_Release( &term->ReadingLock ); - - return pos; -} + if( Offset >= maxlen ) { + LEAVE('-'); + return ; + } -/** - * \brief Write to a virtual terminal - */ -size_t VT_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer) -{ - tVTerm *term = &gVT_Terminals[ Node->Inode ]; - int size; + LOG("maxlen = 0x%x", maxlen); + Length = MIN(Length, maxlen - Offset); - // Write - switch( term->Mode ) + // If the terminal is currently shown, write directly to the screen + if( Term == gpVT_CurTerm ) { - // Print Text - case TERM_MODE_TEXT: - VT_int_PutString(term, Buffer, 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; + // Center the terminal vertically + if( giVT_RealHeight > Term->Height ) { + Offset += (giVT_RealHeight - Term->Height) / 2 * Term->Width * 4; + LOG("Altered offset 0x%x", Offset); } - // Update screen if needed - if( Node->Inode == giVT_CurrentTerminal ) + // If the terminal is not native width, center it horizontally + if( giVT_RealWidth > Term->Width ) { - 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 + // 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; + + LOG("(%i,%i) %ix%i", x, y, w, h); + + // Center + x += (giVT_RealWidth - Term->Width) / 2; + dst_ofs = (x + y * giVT_RealWidth) * 4; + while(h--) { - return VFS_WriteAt( giVT_OutputDevHandle, Offset, Length, Buffer ); + VFS_WriteAt( giVT_OutputDevHandle, + dst_ofs, + Term->Width * 4, + Buffer + ); + Buffer = (const Uint32*)Buffer + Term->Width; + dst_ofs += giVT_RealWidth * 4; } } + // otherwise, just go directly to the screen 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 ); + VFS_WriteAt( giVT_OutputDevHandle, Offset, Length, Buffer ); } + } + // If not active, write to the backbuffer (allocating if needed) + else + { + if( !Term->Buffer ) + Term->Buffer = malloc( Term->Width * Term->Height * 4 ); + LOG("Direct to cache"); + // Copy to the local cache + memcpy( (char*)Term->Buffer + Offset, Buffer, Length ); + } + LEAVE('-'); +} + +void VT_PTYOutput(void *Handle, size_t Length, const void *Data) +{ + tVTerm *term = Handle; + switch( term->Mode ) + { + case PTYBUFFMT_TEXT: + VT_int_PutString(term, Data, Length); 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_FB: + // TODO: How do offset? + VT_int_PutFBData(term, 0, Length, Data); + break; + case PTYBUFFMT_2DCMD: + // TODO: Impliment 2D commands + VT_int_Handle2DCmd(term, Length, Data); + 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); + + memset(&term->Cmd2D, 0, sizeof(term->Cmd2D)); + + if( term == gpVT_CurTerm ) { + switch(term->Mode) + { + case PTYBUFFMT_TEXT: + VT_SetMode(VIDEO_BUFFMT_TEXT); + break; + default: + VT_SetMode(VIDEO_BUFFMT_FRAMEBUFFER); + break; + } + } + 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 @@ -720,6 +620,7 @@ void VT_Terminal_Close(tVFS_Node *Node) { // Remove PID from list } +#endif /** * \fn void VT_SetTerminal(int ID) @@ -734,11 +635,10 @@ 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; @@ -752,6 +652,7 @@ void VT_SetTerminal(int ID) gpVT_CurTerm->Buffer ); } + LOG("Cached screen contents"); } // Update current terminal ID @@ -761,7 +662,7 @@ void VT_SetTerminal(int ID) LOG("Attempting VT_SetMode"); - if( gpVT_CurTerm->Mode == TERM_MODE_TEXT ) + if( gpVT_CurTerm->Mode == PTYBUFFMT_TEXT ) { VT_SetMode( VIDEO_BUFFMT_TEXT ); }