+ int *iData = Data;
+ int ret;
+ 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)
+ {
+ // --- Core Defined
+ 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)
+ {
+ if( CheckMem(Data, sizeof(int)) == 0 ) {
+ LEAVE('i', -1);
+ return -1;
+ }
+ Log_Log("VTerm", "VTerm %i mode set to %i", (int)Node->Inode, *iData);
+
+ // Update mode if needed
+ if( term->Mode != *iData || term->NewWidth || term->NewHeight)
+ {
+ // Adjust for text mode
+ if( *iData == TERM_MODE_TEXT ) {
+ term->NewHeight *= giVT_CharHeight;
+ term->NewWidth *= giVT_CharWidth;
+ }
+ // Fill unchanged dimensions
+ if(term->NewHeight == 0) term->NewHeight = term->Height;
+ if(term->NewWidth == 0) term->NewWidth = term->Width;
+ // Set new mode
+ VT_int_ChangeMode(term, *iData, term->NewWidth, term->NewHeight);
+ // Clear unapplied dimensions
+ term->NewWidth = 0;
+ term->NewHeight = 0;
+ }
+
+ // Update the screen dimensions
+ if(Node->Inode == giVT_CurrentTerminal)
+ VT_SetTerminal( giVT_CurrentTerminal );
+ }
+ LEAVE('i', term->Mode);
+ return term->Mode;
+
+ // Get/set the terminal width
+ case TERM_IOCTL_WIDTH:
+ if(Data != NULL) {
+ if( CheckMem(Data, sizeof(int)) == 0 ) {
+ LEAVE('i', -1);
+ return -1;
+ }
+ term->NewWidth = *iData;
+ }
+ if( term->NewWidth )
+ ret = term->NewWidth;
+ else if( term->Mode == TERM_MODE_TEXT )
+ ret = term->TextWidth;
+ else
+ ret = term->Width;
+ LEAVE('i', ret);
+ return ret;
+
+ // Get/set the terminal height
+ case TERM_IOCTL_HEIGHT:
+ if(Data != NULL) {
+ if( CheckMem(Data, sizeof(int)) == 0 ) {
+ LEAVE('i', -1);
+ return -1;
+ }
+ term->NewHeight = *iData;
+ }
+ if( term->NewHeight )
+ ret = term->NewHeight;
+ else if( term->Mode == TERM_MODE_TEXT )
+ ret = term->TextHeight;
+ else
+ ret = term->Height;
+ LEAVE('i', ret);
+ return ret;
+
+ 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;
+
+ case TERM_IOCTL_GETSETCURSOR:
+ if(Data != NULL)
+ {
+ tVideo_IOCtl_Pos *pos = Data;
+ if( !CheckMem(Data, sizeof(*pos)) ) {
+ errno = -EINVAL;
+ LEAVE('i', -1);
+ return -1;
+ }
+
+ if( term->Mode == TERM_MODE_TEXT )
+ {
+ if(term->Flags & VT_FLAG_ALTBUF)
+ term->AltWritePos = pos->x + pos->y * term->TextWidth;
+ else
+ term->WritePos = pos->x + pos->y * term->TextWidth + term->ViewPos;
+ VT_int_UpdateCursor(term, 0);
+ }
+ else
+ {
+ term->VideoCursorX = pos->x;
+ term->VideoCursorY = pos->y;
+ VT_int_UpdateCursor(term, 1);
+ }
+ }
+ ret = (term->Flags & VT_FLAG_ALTBUF) ? term->AltWritePos : term->WritePos-term->ViewPos;
+ LEAVE('i', ret);
+ return ret;
+
+ case TERM_IOCTL_SETCURSORBITMAP: {
+ tVideo_IOCtl_Bitmap *bmp = Data;
+ if( Data == NULL )
+ {
+ free( term->VideoCursor );
+ term->VideoCursor = NULL;
+ LEAVE('i', 0);
+ return 0;
+ }
+
+ // Sanity check bitmap
+ if( !CheckMem(bmp, sizeof(tVideo_IOCtl_Bitmap)) ) {
+ Log_Notice("VTerm", "%p in TERM_IOCTL_SETCURSORBITMAP invalid", bmp);
+ errno = -EINVAL;
+ LEAVE_RET('i', -1);
+ }
+ if( !CheckMem(bmp->Data, bmp->W*bmp->H*sizeof(Uint32)) ) {
+ Log_Notice("VTerm", "%p in TERM_IOCTL_SETCURSORBITMAP invalid", bmp);
+ errno = -EINVAL;
+ LEAVE_RET('i', -1);
+ }
+
+ // Reallocate if needed
+ if(term->VideoCursor)
+ {
+ if(bmp->W * bmp->H != term->VideoCursor->W * term->VideoCursor->H) {
+ free(term->VideoCursor);
+ term->VideoCursor = NULL;
+ }
+ }
+ if(!term->VideoCursor) {
+ term->VideoCursor = malloc(sizeof(tVideo_IOCtl_Pos) + bmp->W*bmp->H*sizeof(Uint32));
+ if(!term->VideoCursor) {
+ Log_Error("VTerm", "Unable to allocate memory for cursor");
+ errno = -ENOMEM;
+ LEAVE_RET('i', -1);
+ }
+ }
+
+ memcpy(term->VideoCursor, bmp, sizeof(tVideo_IOCtl_Pos) + bmp->W*bmp->H*sizeof(Uint32));
+
+ Log_Debug("VTerm", "Set VT%i's cursor to %p %ix%i",
+ (int)term->Node.Inode, bmp, bmp->W, bmp->H);
+
+ if(gpVT_CurTerm == term)
+ VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSORBITMAP, term->VideoCursor);
+
+ LEAVE('i', 0);
+ return 0; }
+ }
+ LEAVE('i', -1);
+ return -1;
+}
+
+/**
+ * \fn void VT_SetTerminal(int ID)
+ * \brief Set the current terminal
+ */
+void VT_SetTerminal(int ID)
+{
+ // Update current terminal ID
+ Log_Log("VTerm", "Changed terminal from %i to %i", giVT_CurrentTerminal, ID);
+ giVT_CurrentTerminal = ID;
+ gpVT_CurTerm = &gVT_Terminals[ID];
+
+
+ if( gpVT_CurTerm->Mode == TERM_MODE_TEXT )
+ {
+ VT_SetMode( VIDEO_BUFFMT_TEXT );
+ }
+ else
+ {
+ // Update the cursor image
+ if(gpVT_CurTerm->VideoCursor)
+ VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSORBITMAP, gpVT_CurTerm->VideoCursor);
+ VT_SetMode( VIDEO_BUFFMT_FRAMEBUFFER );
+ }
+
+
+ VT_int_UpdateCursor(gpVT_CurTerm, 1);
+ // Update the screen
+ VT_int_UpdateScreen( gpVT_CurTerm, 1 );