X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=KernelLand%2FKernel%2Fdrv%2Fvterm.c;h=217557058c0376ae5507092f951d9e037ebd7d07;hb=3c283c4831c40c14d308a54cefb997832a860bca;hp=2ae38ee894c602430190a667d7f050eaca3f6578;hpb=48743e39650eb1ef988380e9d95f27fd40d3a9ce;p=tpg%2Facess2.git diff --git a/KernelLand/Kernel/drv/vterm.c b/KernelLand/Kernel/drv/vterm.c index 2ae38ee8..21755705 100644 --- a/KernelLand/Kernel/drv/vterm.c +++ b/KernelLand/Kernel/drv/vterm.c @@ -1,5 +1,9 @@ /* - * Acess2 Virtual Terminal Driver + * Acess2 Kernel + * - By John Hodge (thePowersGang) + * + * drv/vterm.c + * - Virtual Terminal - Initialisation and VFS Interface */ #define DEBUG 0 #include "vterm.h" @@ -16,11 +20,10 @@ #define NUM_VTS 8 //#define DEFAULT_OUTPUT "BochsGA" #define DEFAULT_OUTPUT "Vesa" -#define FALLBACK_OUTPUT "x86_VGAText" -#define DEFAULT_INPUT "PS2Keyboard" +#define DEFAULT_INPUT "Keyboard" #define DEFAULT_WIDTH 640 #define DEFAULT_HEIGHT 480 -#define DEFAULT_SCROLLBACK 2 // 2 Screens of text + current screen +#define DEFAULT_SCROLLBACK 4 // 2 Screens of text + current screen //#define DEFAULT_SCROLLBACK 0 // === TYPES === @@ -30,33 +33,23 @@ extern void Debug_SetKTerminal(const char *File); // === 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); -Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer); -Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer); - int VT_Terminal_IOCtl(tVFS_Node *Node, int Id, 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, DEFAULT_INPUT, 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, @@ -103,15 +96,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 ); @@ -122,20 +115,26 @@ 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; } if(!gsVT_InputDevice) gsVT_InputDevice = (char*)DEFAULT_INPUT; else if( Module_EnsureLoaded( gsVT_InputDevice ) ) gsVT_InputDevice = (char*)DEFAULT_INPUT; + if( Module_EnsureLoaded( gsVT_InputDevice ) ) { + Log_Error("VTerm", "Fallback input '%s' is not avaliable, input will not be avaliable", DEFAULT_INPUT); + } // Create device paths { @@ -157,38 +156,39 @@ int VT_Install(char **Arguments) 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; - 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 DevFS_AddDevice( &gVT_DrvInfo ); // Set kernel output to VT0 - Debug_SetKTerminal("/Devices/VTerm/0"); + Log_Debug("VTerm", "Setting kernel output to VT#0"); + Debug_SetKTerminal("/Devices/pts/vt0"); return MODULE_ERR_OK; } @@ -216,7 +216,7 @@ void VT_SetResolution(int Width, int Height) if( Width != mode.width || Height != mode.height ) { Log_Warning("VTerm", - "Selected resolution (%ix%i is not supported) by the device, using (%ix%i)", + "Selected resolution (%ix%i) is not supported by the device, using (%ix%i)", giVT_RealWidth, giVT_RealHeight, mode.width, mode.height ); @@ -226,6 +226,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) @@ -251,49 +252,6 @@ void VT_SetResolution(int Width, int Height) } } -/** - * \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 @@ -334,174 +292,130 @@ int VT_Root_IOCtl(tVFS_Node *Node, int Id, void *Data) return 0; } -/** - * \brief Read from a virtual terminal - */ -Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 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 ); - - // 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 - pos) - avail = Length - pos; - - 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 - pos) - avail = Length - pos; - - codepoint_in = (void*)term->InputBuffer; - codepoint_buf = Buffer; - - 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 ; + } -/** - * \fn Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer) - * \brief Write to a virtual terminal - */ -Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 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 can the offset be done cleanly? (Ask the PTY for its offset?) + Warning("TODO: Offsets for VT_PTYOutput FBData"); + VT_int_PutFBData(term, 0, Length, Data); + break; + case PTYBUFFMT_2DCMD: + VT_int_Handle2DCmd(term, Length, Data); + break; + case PTYBUFFMT_3DCMD: + // TODO: Implement 3D commands + Warning("TODO: VTerm 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 @@ -697,6 +611,17 @@ int VT_Terminal_IOCtl(tVFS_Node *Node, int Id, void *Data) return -1; } +void VT_Terminal_Reference(tVFS_Node *Node) +{ + // Append PID to list +} + +void VT_Terminal_Close(tVFS_Node *Node) +{ + // Remove PID from list +} +#endif + /** * \fn void VT_SetTerminal(int ID) * \brief Set the current terminal @@ -710,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; @@ -728,6 +652,7 @@ void VT_SetTerminal(int ID) gpVT_CurTerm->Buffer ); } + LOG("Cached screen contents"); } // Update current terminal ID @@ -735,7 +660,9 @@ void VT_SetTerminal(int ID) giVT_CurrentTerminal = ID; gpVT_CurTerm = &gVT_Terminals[ID]; - if( gpVT_CurTerm->Mode == TERM_MODE_TEXT ) + LOG("Attempting VT_SetMode"); + + if( gpVT_CurTerm->Mode == PTYBUFFMT_TEXT ) { VT_SetMode( VIDEO_BUFFMT_TEXT ); } @@ -746,7 +673,9 @@ void VT_SetTerminal(int ID) VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSORBITMAP, gpVT_CurTerm->VideoCursor); VT_SetMode( VIDEO_BUFFMT_FRAMEBUFFER ); } - + + LOG("Mode set"); + if(gpVT_CurTerm->Buffer) { // TODO: Handle non equal sized @@ -756,9 +685,11 @@ void VT_SetTerminal(int ID) gpVT_CurTerm->Width*gpVT_CurTerm->Height*sizeof(Uint32), gpVT_CurTerm->Buffer ); + LOG("Updated screen contents"); } VT_int_UpdateCursor(gpVT_CurTerm, 1); // Update the screen VT_int_UpdateScreen(gpVT_CurTerm, 1); + LOG("done"); }