X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;ds=sidebyside;f=Kernel%2Fdrv%2Fvterm.c;h=8255f6c79564b7886ea1f36f20caf8a485cd962c;hb=f9c3c4a68ba22b00df9441631a8513198c8859a5;hp=4095feb76ad49823a61b115b5e41942508fa8d64;hpb=1e7db40300bc594cf708bb6082a6e05a268da946;p=tpg%2Facess2.git diff --git a/Kernel/drv/vterm.c b/Kernel/drv/vterm.c index 4095feb7..8255f6c7 100644 --- a/Kernel/drv/vterm.c +++ b/Kernel/drv/vterm.c @@ -1,7 +1,8 @@ /* * Acess2 Virtual Terminal Driver */ -#include +#define DEBUG 0 +#include #include #include #include @@ -9,15 +10,18 @@ #include #include +#define USE_CTRL_ALT 0 + // === CONSTANTS === #define VERSION ((0<<8)|(50)) -#define NUM_VTS 7 +#define NUM_VTS 8 #define MAX_INPUT_CHARS32 64 #define MAX_INPUT_CHARS8 (MAX_INPUT_CHARS32*4) -#define VT_SCROLLBACK 1 // 2 Screens of text -#define DEFAULT_OUTPUT "VGA" +#define VT_SCROLLBACK 2 // 2 Screens of text +//#define DEFAULT_OUTPUT "VGA" //#define DEFAULT_OUTPUT "BochsGA" +#define DEFAULT_OUTPUT "Vesa" #define DEFAULT_INPUT "PS2Keyboard" #define DEFAULT_WIDTH 80 #define DEFAULT_HEIGHT 25 @@ -38,13 +42,10 @@ typedef struct { int Flags; //!< Flags (see VT_FLAG_*) short Width; //!< Virtual Width short Height; //!< Virtual Height - short RealWidth; //!< Real Width - short RealHeight; //!< Real Height int ViewPos; //!< View Buffer Offset (Text Only) int WritePos; //!< Write Buffer Offset (Text Only) Uint32 CurColour; //!< Current Text Colour - char Name[2]; //!< Name of the terminal int InputRead; //!< Input buffer read position int InputWrite; //!< Input buffer write position @@ -53,6 +54,7 @@ typedef struct { tVT_Char *Text; Uint32 *Buffer; }; + char Name[2]; //!< Name of the terminal tVFS_Node Node; } tVTerm; @@ -61,12 +63,15 @@ extern void Debug_SetKTerminal(char *File); // === PROTOTYPES === int VT_Install(char **Arguments); +void VT_InitOutput(void); +void VT_InitInput(void); char *VT_ReadDir(tVFS_Node *Node, int Pos); tVFS_Node *VT_FindDir(tVFS_Node *Node, 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, void *Buffer); int VT_Terminal_IOCtl(tVFS_Node *Node, int Id, void *Data); +void VT_SetResolution(int IsTextMode, int Width, int Height); void VT_SetTerminal(int ID); void VT_KBCallBack(Uint32 Codepoint); void VT_int_PutString(tVTerm *Term, Uint8 *Buffer, Uint Count); @@ -98,6 +103,10 @@ tDevFS_Driver gVT_DrvInfo = { // --- Terminals --- tVTerm gVT_Terminals[NUM_VTS]; int giVT_CurrentTerminal = 0; +tVTerm *gpVT_CurTerm = &gVT_Terminals[0]; +// --- Video State --- +short giVT_RealWidth; //!< Real Width +short giVT_RealHeight; //!< Real Height // --- Driver Handles --- char *gsVT_OutputDevice = NULL; char *gsVT_InputDevice = NULL; @@ -145,7 +154,6 @@ int VT_Install(char **Arguments) strcpy(gsVT_InputDevice, args[1]); args ++; break; - } } } @@ -154,8 +162,8 @@ int VT_Install(char **Arguments) if(!gsVT_OutputDevice) gsVT_OutputDevice = "/Devices/"DEFAULT_OUTPUT; if(!gsVT_InputDevice) gsVT_InputDevice = "/Devices/"DEFAULT_INPUT; - LOG("Using '%s' as output", gsVT_OutputDevice); - LOG("Using '%s' as input", gsVT_InputDevice); + Log_Log("VTerm", "Using '%s' as output", gsVT_OutputDevice); + Log_Log("VTerm", "Using '%s' as input", gsVT_InputDevice); // Create Nodes for( i = 0; i < NUM_VTS; i++ ) @@ -184,10 +192,14 @@ int VT_Install(char **Arguments) // Add to DevFS DevFS_AddDevice( &gVT_DrvInfo ); + VT_InitOutput(); + VT_InitInput(); + // Set kernel output to VT0 Debug_SetKTerminal("/Devices/VTerm/0"); - return 0; + Log_Log("VTerm", "Returning %i", MODULE_ERR_OK); + return MODULE_ERR_OK; } /** @@ -197,7 +209,12 @@ int VT_Install(char **Arguments) void VT_InitOutput() { giVT_OutputDevHandle = VFS_Open(gsVT_OutputDevice, VFS_OPENFLAG_WRITE); + if(giVT_InputDevHandle == -1) { + Log_Warning("VTerm", "Oh F**k, I can't open the video device '%s'", gsVT_OutputDevice); + return ; + } VT_SetTerminal( 0 ); + VT_SetResolution(1, 640, 400); } /** @@ -230,7 +247,7 @@ tVFS_Node *VT_FindDir(tVFS_Node *Node, char *Name) { int num; - //ENTER("pNode sName", Node, Name); + ENTER("pNode sName", Node, Name); // Open the input and output files if needed if(giVT_OutputDevHandle == -2) VT_InitOutput(); @@ -248,7 +265,7 @@ tVFS_Node *VT_FindDir(tVFS_Node *Node, char *Name) return NULL; } // Return node - //LEAVE('p', &gVT_Terminals[num].Node); + LEAVE('p', &gVT_Terminals[num].Node); return &gVT_Terminals[num].Node; } @@ -314,8 +331,8 @@ Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) } break; - case TERM_MODE_FB: - case TERM_MODE_OPENGL: + //case TERM_MODE_FB: + default: while(pos < Length) { while(term->InputRead == term->InputWrite) Threads_Yield(); @@ -336,8 +353,7 @@ Uint64 VT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) { tVTerm *term = &gVT_Terminals[ Node->Inode ]; - - //ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer); + int size; // Write switch( term->Mode ) @@ -345,9 +361,48 @@ Uint64 VT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) case TERM_MODE_TEXT: VT_int_PutString(term, Buffer, Length); break; + case TERM_MODE_FB: + 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; + } + + memcpy( (void*)((Uint)term->Buffer + (Uint)Offset), Buffer, Length ); + + if( Node->Inode == giVT_CurrentTerminal ) + { + if( giVT_RealWidth > term->Width || giVT_RealHeight > term->Height ) + { + #if 0 + int x, y, h; + x = Offset/4; y = x / term->Width; x %= term->Width; + w = Length/4+x; h = w / term->Width; w %= term->Width; + while(h--) + { + VFS_WriteAt( giVT_OutputDevHandle, + (x+y*term->RealWidth)*4, + term->Width * 4, + Buffer + ); + Buffer = (void*)( (Uint)Buffer + term->Width*term->Height*4 ); + } + #endif + return 0; + } + else { + return VFS_WriteAt( giVT_OutputDevHandle, Offset, Length, Buffer ); + } + } } - //LEAVE('i', 0); return 0; } @@ -359,77 +414,117 @@ int VT_Terminal_IOCtl(tVFS_Node *Node, int Id, void *Data) { int *iData = Data; tVTerm *term = Node->ImplPtr; + ENTER("pNode iId pData", Node, Id, Data); + + if(Id >= DRV_IOCTL_LOOKUP) { + // Only root can fiddle with graphics modes + // TODO: Remove this and replace with user ownership + if( Threads_GetUID() != 0 ) return -1; + } + switch(Id) { - case DRV_IOCTL_TYPE: return DRV_TYPE_TERMINAL; - case DRV_IOCTL_IDENT: memcpy(Data, "VT\0\0", 4); return 0; - case DRV_IOCTL_VERSION: return VERSION; - case DRV_IOCTL_LOOKUP: return 0; + case DRV_IOCTL_TYPE: + LEAVE('i', DRV_TYPE_TERMINAL); + return DRV_TYPE_TERMINAL; + case DRV_IOCTL_IDENT: + memcpy(Data, "VT\0\0", 4); + LEAVE('i', 0); + return 0; + case DRV_IOCTL_VERSION: + LEAVE('x', VERSION); + return VERSION; + case DRV_IOCTL_LOOKUP: + LEAVE('i', 0); + return 0; // Get/Set the mode (and apply any changes) case TERM_IOCTL_MODETYPE: - if(Data == NULL) return term->Mode; - - if(term->Mode != *iData) { - VT_int_ChangeMode(term, *iData); + if(Data != NULL) + { + Log_Log("VTerm", "VTerm %i mode set to %i", (int)Node->Inode, *iData); + // Update mode if needed + if(term->Mode != *iData) + VT_int_ChangeMode(term, *iData); + + // Update the screen dimensions + if(Node->Inode == giVT_CurrentTerminal) + VT_SetTerminal( giVT_CurrentTerminal ); } - - // Update the screen dimensions - if(giVT_CurrentTerminal == Node->Inode) - VT_SetTerminal( giVT_CurrentTerminal ); - break; + LEAVE('i', term->Mode); + return term->Mode; // Get/set the terminal width case TERM_IOCTL_WIDTH: - if(Data == NULL) return term->Width; - term->Width = *iData; - break; + if(Data != NULL) term->Width = *iData; + Log("VT_Terminal_IOCtl - RETURN term->Width = %i", term->Width); + LEAVE('i', term->Width); + return term->Width; // Get/set the terminal height case TERM_IOCTL_HEIGHT: - if(Data == NULL) return term->Height; - term->Height = *iData; - break; + if(Data != NULL) term->Height = *iData; + Log("VT_Terminal_IOCtl - RETURN term->Height = %i", term->Height); + LEAVE('i', term->Height); + return term->Height; - default: - return -1; + case TERM_IOCTL_FORCESHOW: + Log_Log("VTerm", "Thread %i forced VTerm %i to be shown", + Threads_GetTID(), (int)Node->Inode); + VT_SetTerminal( Node->Inode ); + LEAVE('i', 1); + return 1; } - return 0; + LEAVE('i', -1); + return -1; } -/** - * \fn void VT_SetTerminal(int ID) - * \brief Set the current terminal - */ -void VT_SetTerminal(int ID) +void VT_SetResolution(int IsTextMode, int Width, int Height) { tVideo_IOCtl_Mode mode = {0}; - int modeNum; + int tmp; // Create the video mode - mode.width = gVT_Terminals[ ID ].Width; - mode.height = gVT_Terminals[ ID ].Height; - // - Text Mode - if(gVT_Terminals[ ID ].Mode == TERM_MODE_TEXT) { - mode.bpp = 12; - mode.flags = VIDEO_FLAG_TEXT; - } - // - Framebuffer or 3D - else { - mode.bpp = 32; - mode.flags = 0; - } + mode.width = Width; + mode.height = Height; + mode.bpp = 32; + mode.flags = 0; // Set video mode VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_FINDMODE, &mode ); - modeNum = mode.id; - gVT_Terminals[ ID ].RealWidth = mode.width; - gVT_Terminals[ ID ].RealHeight = mode.height; - VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_GETSETMODE, &modeNum ); + tmp = mode.id; + giVT_RealWidth = mode.width; + giVT_RealHeight = mode.height; + VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_GETSETMODE, &tmp ); + tmp = IsTextMode ? VIDEO_BUFFMT_TEXT : VIDEO_BUFFMT_FRAMEBUFFER; + VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_SETBUFFORMAT, &tmp ); +} + +/** + * \fn void VT_SetTerminal(int ID) + * \brief Set the current terminal + */ +void VT_SetTerminal(int ID) +{ // Update current terminal ID - Log("Changed terminal from %i to %i", giVT_CurrentTerminal, ID); + Log_Log("VTerm", "Changed terminal from %i to %i", giVT_CurrentTerminal, ID); giVT_CurrentTerminal = ID; + gpVT_CurTerm = &gVT_Terminals[ID]; + + // Update cursor + if( gpVT_CurTerm->Mode == TERM_MODE_TEXT && !(gpVT_CurTerm->Flags & VT_FLAG_HIDECSR) ) + { + tVideo_IOCtl_Pos pos; + pos.x = gpVT_CurTerm->WritePos % gpVT_CurTerm->Width; + pos.y = gpVT_CurTerm->WritePos / gpVT_CurTerm->Width; + VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSOR, &pos); + } + + if( gpVT_CurTerm->Mode == TERM_MODE_TEXT ) + VT_SetResolution( 1, gpVT_CurTerm->Width*giVT_CharWidth, gpVT_CurTerm->Height*giVT_CharHeight ); + else + VT_SetResolution( 0, gpVT_CurTerm->Width, gpVT_CurTerm->Height ); // Update the screen VT_int_UpdateScreen( &gVT_Terminals[ ID ], 1 ); @@ -438,6 +533,11 @@ void VT_SetTerminal(int ID) /** * \fn void VT_KBCallBack(Uint32 Codepoint) * \brief Called on keyboard interrupt + * \param Codepoint Pseudo-UTF32 character + * + * Handles a key press and sends the key code to the user's buffer. + * If the code creates a kernel-magic sequence, it is not passed to the + * user and is handled in-kernel. */ void VT_KBCallBack(Uint32 Codepoint) { @@ -452,6 +552,10 @@ void VT_KBCallBack(Uint32 Codepoint) Codepoint &= 0x7FFFFFFF; switch(Codepoint) { + #if !USE_CTRL_ALT + case KEY_RSHIFT: gbVT_CtrlDown = 0; break; + case KEY_LSHIFT: gbVT_AltDown = 0; break; + #else case KEY_LALT: case KEY_RALT: gbVT_AltDown = 0; @@ -460,12 +564,17 @@ void VT_KBCallBack(Uint32 Codepoint) case KEY_RCTRL: gbVT_CtrlDown = 0; break; + #endif } return; } switch(Codepoint) { + #if !USE_CTRL_ALT + case KEY_RSHIFT: gbVT_CtrlDown = 1; break; + case KEY_LSHIFT: gbVT_AltDown = 1; break; + #else case KEY_LALT: case KEY_RALT: gbVT_AltDown = 1; @@ -474,10 +583,13 @@ void VT_KBCallBack(Uint32 Codepoint) case KEY_RCTRL: gbVT_CtrlDown = 1; break; + #endif default: + #if USE_CTRL_ALT if(!gbVT_AltDown || !gbVT_CtrlDown) break; + #endif switch(Codepoint) { case KEY_F1: VT_SetTerminal(0); return; @@ -493,8 +605,16 @@ void VT_KBCallBack(Uint32 Codepoint) case KEY_F11: VT_SetTerminal(10); return; case KEY_F12: VT_SetTerminal(11); return; case KEY_PGUP: + if( gpVT_CurTerm->ViewPos > gpVT_CurTerm->Width ) + gpVT_CurTerm->ViewPos -= gpVT_CurTerm->Width; + else + gpVT_CurTerm->ViewPos = 0; return; case KEY_PGDOWN: + if( gpVT_CurTerm->ViewPos < gpVT_CurTerm->Width*(gpVT_CurTerm->Height*(VT_SCROLLBACK-1)) ) + gpVT_CurTerm->ViewPos += gpVT_CurTerm->Width; + else + gpVT_CurTerm->ViewPos = gpVT_CurTerm->Width*(gpVT_CurTerm->Height*(VT_SCROLLBACK-1)); return; } } @@ -579,41 +699,6 @@ void VT_KBCallBack(Uint32 Codepoint) } } -/** - * \fn void VT_int_PutString(tVTerm *Term, Uint8 *Buffer, Uint Count) - * \brief Print a string to the Virtual Terminal - */ -void VT_int_PutString(tVTerm *Term, Uint8 *Buffer, Uint Count) -{ - Uint32 val; - int i; - for( i = 0; i < Count; i++ ) - { - if( Buffer[i] == 0x1B ) // Escape Sequence - { - i ++; - i += VT_int_ParseEscape(Term, (char*)&Buffer[i]); - continue; - } - - if( Buffer[i] < 128 ) // Plain ASCII - VT_int_PutChar(Term, Buffer[i]); - else { // UTF-8 - i += ReadUTF8(&Buffer[i], &val); - VT_int_PutChar(Term, val); - } - } - - // Update cursor - if( !(Term->Flags & VT_FLAG_HIDECSR) ) - { - tVideo_IOCtl_Pos pos; - pos.x = Term->WritePos % Term->Width; - pos.y = Term->WritePos / Term->Width; - VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSOR, &pos); - } -} - /** * \fn void VT_int_ClearLine(tVTerm *Term, int Num) * \brief Clears a line in a virtual terminal @@ -742,6 +827,43 @@ int VT_int_ParseEscape(tVTerm *Term, char *Buffer) return j + 1; } +/** + * \fn void VT_int_PutString(tVTerm *Term, Uint8 *Buffer, Uint Count) + * \brief Print a string to the Virtual Terminal + */ +void VT_int_PutString(tVTerm *Term, Uint8 *Buffer, Uint Count) +{ + Uint32 val; + int i; + for( i = 0; i < Count; i++ ) + { + if( Buffer[i] == 0x1B ) // Escape Sequence + { + i ++; + i += VT_int_ParseEscape(Term, (char*)&Buffer[i]); + continue; + } + + if( Buffer[i] < 128 ) // Plain ASCII + VT_int_PutChar(Term, Buffer[i]); + else { // UTF-8 + i += ReadUTF8(&Buffer[i], &val); + VT_int_PutChar(Term, val); + } + } + // Update Screen + VT_int_UpdateScreen( Term, 0 ); + + // Update cursor + if( Term == gpVT_CurTerm && !(Term->Flags & VT_FLAG_HIDECSR) ) + { + tVideo_IOCtl_Pos pos; + pos.x = Term->WritePos % Term->Width; + pos.y = Term->WritePos / Term->Width; + VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSOR, &pos); + } +} + /** * \fn void VT_int_PutChar(tVTerm *Term, Uint32 Ch) * \brief Write a single character to a VTerm @@ -750,12 +872,13 @@ void VT_int_PutChar(tVTerm *Term, Uint32 Ch) { int i; //ENTER("pTerm xCh", Term, Ch); - //LOG("Term = {WritePos:%i, ViewPos:%i}\n", Term->WritePos, Term->ViewPos); + //LOG("Term = {WritePos:%i, ViewPos:%i}", Term->WritePos, Term->ViewPos); switch(Ch) { case '\0': return; // Ignore NULL byte case '\n': + VT_int_UpdateScreen( Term, 0 ); // Update the line before newlining Term->WritePos += Term->Width; case '\r': Term->WritePos -= Term->WritePos % Term->Width; @@ -817,7 +940,7 @@ void VT_int_PutChar(tVTerm *Term, Uint32 Ch) memcpy( Term->Text, &Term->Text[Term->Width], - Term->Width*(Term->Height-1)*VT_SCROLLBACK*sizeof(tVT_Char) + (Term->Width*Term->Height*VT_SCROLLBACK-Term->Width)*sizeof(tVT_Char) ); // Clear last row @@ -827,15 +950,15 @@ void VT_int_PutChar(tVTerm *Term, Uint32 Ch) Term->Text[ base + i ].Colour = Term->CurColour; } + //LOG("Scrolled buffer"); VT_int_UpdateScreen( Term, 1 ); } - else if(Term->WritePos > Term->Width*Term->Height+Term->ViewPos) + else if(Term->WritePos >= Term->Width*Term->Height+Term->ViewPos) { Term->ViewPos += Term->Width; + //LOG("Scrolled screen"); VT_int_UpdateScreen( Term, 1 ); } - else - VT_int_UpdateScreen( Term, 0 ); //LEAVE('-'); } @@ -847,11 +970,15 @@ void VT_int_PutChar(tVTerm *Term, Uint32 Ch) void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll ) { // Only update if this is the current terminal - if( Term != &gVT_Terminals[giVT_CurrentTerminal] ) return; + if( Term != gpVT_CurTerm ) return; - if( Term->Mode == TERM_MODE_TEXT ) + switch( Term->Mode ) { + case TERM_MODE_TEXT: if(UpdateAll) { + //LOG("UpdateAll = 1"); + //LOG("VFS_WriteAt(0x%x, 0, %i*sizeof(tVT_Char), &Term->Text[%i])", + // giVT_OutputDevHandle, Term->Width*Term->Height, Term->ViewPos); VFS_WriteAt( giVT_OutputDevHandle, 0, @@ -860,6 +987,9 @@ void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll ) ); } else { int pos = Term->WritePos - Term->WritePos % Term->Width; + //LOG("UpdateAll = 0"); + //LOG("VFS_WriteAt(0x%x, %i*sizeof(tVT_Char), %i*sizeof(tVT_Char), &Term->Text[%i])", + // giVT_OutputDevHandle, (pos - Term->ViewPos), Term->Width, pos); VFS_WriteAt( giVT_OutputDevHandle, (pos - Term->ViewPos)*sizeof(tVT_Char), @@ -867,15 +997,15 @@ void VT_int_UpdateScreen( tVTerm *Term, int UpdateAll ) &Term->Text[pos] ); } - } - else - { + break; + case TERM_MODE_FB: VFS_WriteAt( giVT_OutputDevHandle, 0, Term->Width*Term->Height*sizeof(Uint32), - &Term->Buffer + Term->Buffer ); + break; } } @@ -888,15 +1018,20 @@ void VT_int_ChangeMode(tVTerm *Term, int NewMode) switch(NewMode) { case TERM_MODE_TEXT: + Log_Log("VTerm", "Set VT %p to text mode", Term); free(Term->Buffer); Term->Text = calloc( Term->Width*Term->Height*VT_SCROLLBACK, sizeof(tVT_Char) ); break; case TERM_MODE_FB: + Log_Log("VTerm", "Set VT %p to framebuffer mode (%ix%i)", Term, + Term->Width, Term->Height); free(Term->Text); Term->Buffer = calloc( Term->Width*Term->Height, sizeof(Uint32) ); + Log_Debug("VTerm", "Term->Buffer = %p", Term->Buffer); break; - case TERM_MODE_OPENGL: - return; + //case TERM_MODE_2DACCEL: + //case TERM_MODE_3DACCEL: + // return; } Term->Mode = NewMode; @@ -917,7 +1052,7 @@ void VT_int_ChangeMode(tVTerm *Term, int NewMode) Uint8 *VT_Font_GetChar(Uint32 Codepoint); // === GLOBALS === -int giVT_CharWidth = FONT_WIDTH+1; +int giVT_CharWidth = FONT_WIDTH; int giVT_CharHeight = FONT_HEIGHT; // === CODE ===