1556aa81e6c23782c387e0a6901a7b654f6f32a4
[tpg/acess2.git] / KernelLand / Kernel / drv / vterm.c
1 /*
2  * Acess2 Kernel
3  * - By John Hodge (thePowersGang)
4  *
5  * drv/vterm.c
6  * - Virtual Terminal - Initialisation and VFS Interface
7  */
8 #define DEBUG   1
9 #include "vterm.h"
10 #include <fs_devfs.h>
11 #include <modules.h>
12 #include <api_drv_keyboard.h>
13 #include <api_drv_video.h>
14 #include <errno.h>
15 #include <semaphore.h>
16
17 // === CONSTANTS ===
18 #define VERSION ((0<<8)|(50))
19
20 #define NUM_VTS 8
21 //#define DEFAULT_OUTPUT        "BochsGA"
22 #define DEFAULT_OUTPUT  "Vesa"
23 #define FALLBACK_OUTPUT "x86_VGAText"
24 #define DEFAULT_INPUT   "Keyboard"
25 #define DEFAULT_WIDTH   640
26 #define DEFAULT_HEIGHT  480
27 #define DEFAULT_SCROLLBACK      4       // 2 Screens of text + current screen
28 //#define DEFAULT_SCROLLBACK    0
29
30 // === TYPES ===
31
32 // === IMPORTS ===
33 extern void     Debug_SetKTerminal(const char *File);
34
35 // === PROTOTYPES ===
36  int    VT_Install(char **Arguments);
37  int    VT_Root_IOCtl(tVFS_Node *Node, int Id, void *Data);
38 void    VT_int_PutFBData(tVTerm *Term, size_t Offset, size_t Length, const void *Data);
39 void    VT_PTYOutput(void *Handle, size_t Length, const void *Data);
40  int    VT_PTYResize(void *Handle, const struct ptydims *Dims); 
41  int    VT_PTYModeset(void *Handle, const struct ptymode *Mode);
42
43 // === CONSTANTS ===
44
45 // === GLOBALS ===
46 MODULE_DEFINE(0, VERSION, VTerm, VT_Install, NULL, "PTY", NULL);
47 tVFS_NodeType   gVT_RootNodeType = {
48         .TypeName = "VTerm Root",
49         .IOCtl = VT_Root_IOCtl
50         };
51 tDevFS_Driver   gVT_DrvInfo = {
52         NULL, "VTerm",
53         {
54         .Flags = 0,
55         .Size = NUM_VTS,
56         .Inode = -1,
57         .NumACLs = 0,
58         .Type = &gVT_RootNodeType
59         }
60 };
61 // --- Terminals ---
62 tVTerm  gVT_Terminals[NUM_VTS];
63  int    giVT_CurrentTerminal = 0;
64 tVTerm  *gpVT_CurTerm = &gVT_Terminals[0];
65 // --- Video State ---
66 short   giVT_RealWidth  = DEFAULT_WIDTH;        //!< Screen Width
67 short   giVT_RealHeight = DEFAULT_HEIGHT;       //!< Screen Height
68  int    giVT_Scrollback = DEFAULT_SCROLLBACK;
69 // --- Driver Handles ---
70 char    *gsVT_OutputDevice = NULL;
71 char    *gsVT_InputDevice = NULL;
72  int    giVT_OutputDevHandle = -2;
73  int    giVT_InputDevHandle = -2;
74
75 // === CODE ===
76 /**
77  * \fn int VT_Install(char **Arguments)
78  * \brief Installs the Virtual Terminal Driver
79  */
80 int VT_Install(char **Arguments)
81 {
82          int    i;
83         
84         // Scan Arguments
85         if(Arguments)
86         {
87                 char    **args;
88                 const char      *arg;
89                 for(args = Arguments; (arg = *args); args++ )
90                 {
91                         char    data[strlen(arg)+1];
92                         char    *opt = data;
93                         char    *val;
94                         
95                         val = strchr(arg, '=');
96                         strcpy(data, arg);
97                         if( val ) {
98                                 data[ val - arg ] = '\0';
99                                 val ++;
100                         }
101                         Log_Debug("VTerm", "Argument '%s'='%s'", opt, val);
102                         
103                         if( strcmp(opt, "Video") == 0 ) {
104                                 if( !gsVT_OutputDevice )
105                                         gsVT_OutputDevice = val;
106                         }
107                         else if( strcmp(opt, "Input") == 0 ) {
108                                 if( !gsVT_InputDevice )
109                                         gsVT_InputDevice = val;
110                         }
111                         else if( strcmp(opt, "Width") == 0 ) {
112                                 giVT_RealWidth = atoi( val );
113                         }
114                         else if( strcmp(opt, "Height") == 0 ) {
115                                 giVT_RealHeight = atoi( val );
116                         }
117                         else if( strcmp(opt, "Scrollback") == 0 ) {
118                                 giVT_Scrollback = atoi( val );
119                         }
120                         else {
121                                 Log_Notice("VTerm", "Unknown option '%s'", opt);
122                         }
123                 }
124         }
125         
126         // Apply Defaults
127         if(!gsVT_OutputDevice)  gsVT_OutputDevice = (char*)DEFAULT_OUTPUT;
128         else if( Module_EnsureLoaded( gsVT_OutputDevice ) )     gsVT_OutputDevice = (char*)DEFAULT_OUTPUT;
129         if( Module_EnsureLoaded( gsVT_OutputDevice ) )  gsVT_OutputDevice = (char*)FALLBACK_OUTPUT;
130         if( Module_EnsureLoaded( gsVT_OutputDevice ) ) {
131                 Log_Error("VTerm", "Fallback video '%s' is not avaliable, giving up", FALLBACK_OUTPUT);
132                 return MODULE_ERR_MISC;
133         }
134         
135         if(!gsVT_InputDevice)   gsVT_InputDevice = (char*)DEFAULT_INPUT;
136         else if( Module_EnsureLoaded( gsVT_InputDevice ) )      gsVT_InputDevice = (char*)DEFAULT_INPUT;
137         if( Module_EnsureLoaded( gsVT_InputDevice ) ) {
138                 Log_Error("VTerm", "Fallback input '%s' is not avaliable, input will not be avaliable", DEFAULT_INPUT);
139         }
140         
141         // Create device paths
142         {
143                 char    *tmp;
144                 tmp = malloc( 9 + strlen(gsVT_OutputDevice) + 1 );
145                 strcpy(tmp, "/Devices/");
146                 strcpy(&tmp[9], gsVT_OutputDevice);
147                 gsVT_OutputDevice = tmp;
148
149                 tmp = malloc( 9 + strlen(gsVT_InputDevice) + 1 );
150                 strcpy(tmp, "/Devices/");
151                 strcpy(&tmp[9], gsVT_InputDevice);
152                 gsVT_InputDevice = tmp;
153         }
154         
155         Log_Log("VTerm", "Using '%s' as output", gsVT_OutputDevice);
156         Log_Log("VTerm", "Using '%s' as input", gsVT_InputDevice);
157         
158         VT_InitOutput();
159         VT_InitInput();
160         
161         
162         // Create Nodes
163         Log_Debug("VTerm", "Initialising nodes (and creating buffers)");
164         for( i = 0; i < NUM_VTS; i++ )
165         {
166                 gVT_Terminals[i].Mode = TERM_MODE_TEXT;
167                 gVT_Terminals[i].Flags = 0;
168 //              gVT_Terminals[i].Flags = VT_FLAG_HIDECSR;       //HACK - Stop all those memcpy calls
169                 gVT_Terminals[i].CurColour = DEFAULT_COLOUR;
170                 gVT_Terminals[i].WritePos = 0;
171                 gVT_Terminals[i].AltWritePos = 0;
172                 gVT_Terminals[i].ViewPos = 0;
173                 gVT_Terminals[i].ScrollHeight = 0;
174                 
175                 // Initialise
176                 VT_int_Resize( &gVT_Terminals[i], giVT_RealWidth, giVT_RealHeight );
177                 gVT_Terminals[i].Mode = PTYBUFFMT_TEXT;
178                 char    name[] = {'v','t','0'+i,'\0'};
179                 struct ptydims dims = {
180                         .W = giVT_RealWidth / giVT_CharWidth,
181                         .H = giVT_RealHeight / giVT_CharHeight,
182                         .PW = giVT_RealWidth,
183                         .PH = giVT_RealHeight
184                 };
185                 struct ptymode mode = {
186                         .OutputMode = PTYBUFFMT_TEXT,
187                         .InputMode = PTYIMODE_CANON|PTYIMODE_ECHO
188                 };
189                 gVT_Terminals[i].PTY = PTY_Create(name, &gVT_Terminals[i],
190                         VT_PTYOutput, VT_PTYResize, VT_PTYModeset,
191                         &dims, &mode);
192         }
193         
194         // Add to DevFS
195         DevFS_AddDevice( &gVT_DrvInfo );
196         
197         // Set kernel output to VT0
198         Log_Debug("VTerm", "Setting kernel output to VT#0");
199         Debug_SetKTerminal("/Devices/pts/vt0");
200         
201         return MODULE_ERR_OK;
202 }
203
204 /**
205  * \brief Set the video resolution
206  * \param Width New screen width
207  * \param Height        New screen height
208  */
209 void VT_SetResolution(int Width, int Height)
210 {
211         tVideo_IOCtl_Mode       mode = {0};
212          int    tmp;
213          int    i;
214         
215         // Create the video mode
216         mode.width = Width;
217         mode.height = Height;
218         mode.bpp = 32;
219         mode.flags = 0;
220         
221         // Set video mode
222         VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_FINDMODE, &mode );
223         tmp = mode.id;
224         if( Width != mode.width || Height != mode.height )
225         {
226                 Log_Warning("VTerm",
227                         "Selected resolution (%ix%i) is not supported by the device, using (%ix%i)",
228                         giVT_RealWidth, giVT_RealHeight,
229                         mode.width, mode.height
230                         );
231                 giVT_RealWidth = mode.width;
232                 giVT_RealHeight = mode.height;
233         }
234         VFS_IOCtl( giVT_OutputDevHandle, VIDEO_IOCTL_GETSETMODE, &tmp );
235         
236         // Resize text terminals if needed
237         // - VT0 check is for the first resolution set
238         if( gVT_Terminals[0].Text && (giVT_RealWidth != mode.width || giVT_RealHeight != mode.height) )
239         {
240                  int    newBufSize = (giVT_RealWidth/giVT_CharWidth)
241                                         *(giVT_RealHeight/giVT_CharHeight)
242                                         *(giVT_Scrollback+1);
243                 //tVT_Char      *tmp;
244                 // Resize the text terminals
245                 Log_Debug("VTerm", "Resizing terminals to %ix%i",
246                         giVT_RealWidth/giVT_CharWidth, giVT_RealHeight/giVT_CharHeight);
247                 for( i = 0; i < NUM_VTS; i ++ )
248                 {
249                         if( gVT_Terminals[i].Mode != TERM_MODE_TEXT )   continue;
250                         
251                         gVT_Terminals[i].TextWidth = giVT_RealWidth/giVT_CharWidth;
252                         gVT_Terminals[i].TextHeight = giVT_RealHeight/giVT_CharHeight;
253                         gVT_Terminals[i].ScrollHeight = gVT_Terminals[i].TextHeight;
254                         
255                         gVT_Terminals[i].Text = realloc(
256                                 gVT_Terminals[i].Text,
257                                 newBufSize*sizeof(tVT_Char)
258                                 );
259                 }
260         }
261 }
262
263 /**
264  * \fn int VT_Root_IOCtl(tVFS_Node *Node, int Id, void *Data)
265  * \brief Control the VTerm Driver
266  */
267 int VT_Root_IOCtl(tVFS_Node *Node, int Id, void *Data)
268 {
269          int    len;
270         switch(Id)
271         {
272         case DRV_IOCTL_TYPE:    return DRV_TYPE_MISC;
273         case DRV_IOCTL_IDENT:   memcpy(Data, "VT\0\0", 4);      return 0;
274         case DRV_IOCTL_VERSION: return VERSION;
275         case DRV_IOCTL_LOOKUP:  return 0;
276         
277         case 4: // Get Video Driver
278                 if(Data)        strcpy(Data, gsVT_OutputDevice);
279                 return strlen(gsVT_OutputDevice);
280         
281         case 5: // Set Video Driver
282                 if(!Data)       return -EINVAL;
283                 if(Threads_GetUID() != 0)       return -EACCES;
284                 
285                 len = strlen(Data);
286                 
287                 // TODO: Check if the string used is a heap string
288                 
289                 free(gsVT_OutputDevice);
290                 
291                 gsVT_OutputDevice = malloc(len+1);
292                 strcpy(gsVT_OutputDevice, Data);
293                 
294                 VFS_Close(giVT_OutputDevHandle);
295                 giVT_OutputDevHandle = -1;
296                 
297                 VT_InitOutput();
298                 return 1;
299         }
300         return 0;
301 }
302
303 void VT_int_PutFBData(tVTerm *Term, size_t Offset, size_t Length, const void *Buffer)
304 {
305         size_t  maxlen = Term->Width * Term->Height * 4;
306
307         ENTER("pTerm xOffset xLength pBuffer", Term, Offset, Length, Buffer);
308
309         if( Offset >= maxlen ) {
310                 LEAVE('-');
311                 return ;
312         }
313
314         LOG("maxlen = 0x%x", maxlen);
315         Length = MIN(Length, maxlen - Offset);
316         
317         // If the terminal is currently shown, write directly to the screen
318         if( Term == gpVT_CurTerm )
319         {
320                 // Center the terminal vertically
321                 if( giVT_RealHeight > Term->Height ) {
322                         Offset += (giVT_RealHeight - Term->Height) / 2 * Term->Width * 4;
323                         LOG("Altered offset 0x%x", Offset);
324                 }
325                 
326                 // If the terminal is not native width, center it horizontally
327                 if( giVT_RealWidth > Term->Width )
328                 {
329                         // No? :( Well, just center it
330                          int    x, y, w, h;
331                         Uint    dst_ofs;
332                         // TODO: Fix to handle the final line correctly?
333                         x = Offset/4;   y = x / Term->Width;    x %= Term->Width;
334                         w = Length/4+x; h = w / Term->Width;    w %= Term->Width;
335
336                         LOG("(%i,%i) %ix%i", x, y, w, h);               
337         
338                         // Center
339                         x += (giVT_RealWidth - Term->Width) / 2;
340                         dst_ofs = (x + y * giVT_RealWidth) * 4;
341                         while(h--)
342                         {
343                                 VFS_WriteAt( giVT_OutputDevHandle,
344                                         dst_ofs,
345                                         Term->Width * 4,
346                                         Buffer
347                                         );
348                                 Buffer = (const Uint32*)Buffer + Term->Width;
349                                 dst_ofs += giVT_RealWidth * 4;
350                         }
351                 }
352                 // otherwise, just go directly to the screen
353                 else
354                 {
355                         VFS_WriteAt( giVT_OutputDevHandle, Offset, Length, Buffer );
356                 }
357         }
358         // If not active, write to the backbuffer (allocating if needed)
359         else
360         {
361                 if( !Term->Buffer )
362                         Term->Buffer = malloc( Term->Width * Term->Height * 4 );
363                 LOG("Direct to cache");
364                 // Copy to the local cache
365                 memcpy( (char*)Term->Buffer + Offset, Buffer, Length );
366         }
367         LEAVE('-');
368 }
369
370 void VT_PTYOutput(void *Handle, size_t Length, const void *Data)
371 {
372         tVTerm  *term = Handle;
373         switch( term->Mode )
374         {
375         case PTYBUFFMT_TEXT:
376                 VT_int_PutString(term, Data, Length);
377                 break;
378         case PTYBUFFMT_FB:
379                 // TODO: How do offset?
380                 VT_int_PutFBData(term, 0, Length, Data);
381                 break;
382         case PTYBUFFMT_2DCMD:
383                 // TODO: Impliment 2D commands
384                 VT_int_Handle2DCmd(term, Length, Data);
385                 break;
386         case PTYBUFFMT_3DCMD:
387                 // TODO: Impliment 3D commands
388                 break;
389         }
390 }
391
392 int VT_PTYResize(void *Handle, const struct ptydims *Dims)
393 {
394         tVTerm  *term = Handle;
395          int    newW = Dims->W * (term->Mode == PTYBUFFMT_TEXT ? giVT_CharWidth : 1);
396          int    newH = Dims->H * (term->Mode == PTYBUFFMT_TEXT ? giVT_CharHeight : 1);
397         if( newW > giVT_RealWidth || newH > giVT_RealHeight )
398                 return 1;
399         VT_int_Resize(term, newW, newH);
400         return 0;
401 }
402
403 int VT_PTYModeset(void *Handle, const struct ptymode *Mode)
404 {
405         tVTerm  *term = Handle;
406         term->Mode = (Mode->OutputMode & PTYOMODE_BUFFMT);
407
408         memset(&term->Cmd2D, 0, sizeof(term->Cmd2D));
409
410         if( term == gpVT_CurTerm ) {
411                 switch(term->Mode)
412                 {
413                 case PTYBUFFMT_TEXT:
414                         VT_SetMode(VIDEO_BUFFMT_TEXT);
415                         break;
416                 default:
417                         VT_SetMode(VIDEO_BUFFMT_FRAMEBUFFER);
418                         break;
419                 }
420         }       
421
422         return 0;
423 }
424
425 #if 0
426 /**
427  * \fn int VT_Terminal_IOCtl(tVFS_Node *Node, int Id, void *Data)
428  * \brief Call an IO Control on a virtual terminal
429  */
430 int VT_Terminal_IOCtl(tVFS_Node *Node, int Id, void *Data)
431 {
432          int    *iData = Data;
433          int    ret;
434         tVTerm  *term = Node->ImplPtr;
435         ENTER("pNode iId pData", Node, Id, Data);
436         
437         if(Id >= DRV_IOCTL_LOOKUP) {
438                 // Only root can fiddle with graphics modes
439                 // TODO: Remove this and replace with user ownership
440                 if( Threads_GetUID() != 0 )     return -1;
441         }
442         
443         switch(Id)
444         {
445         // --- Core Defined
446         case DRV_IOCTL_TYPE:
447                 LEAVE('i', DRV_TYPE_TERMINAL);
448                 return DRV_TYPE_TERMINAL;
449         case DRV_IOCTL_IDENT:
450                 memcpy(Data, "VT\0\0", 4);
451                 LEAVE('i', 0);
452                 return 0;
453         case DRV_IOCTL_VERSION:
454                 LEAVE('x', VERSION);
455                 return VERSION;
456         case DRV_IOCTL_LOOKUP:
457                 LEAVE('i', 0);
458                 return 0;
459         
460         // Get/Set the mode (and apply any changes)
461         case TERM_IOCTL_MODETYPE:
462                 if(Data != NULL)
463                 {
464                         if( CheckMem(Data, sizeof(int)) == 0 ) {
465                                 LEAVE('i', -1);
466                                 return -1;
467                         }
468                         Log_Log("VTerm", "VTerm %i mode set to %i", (int)Node->Inode, *iData);
469                         
470                         // Update mode if needed
471                         if( term->Mode != *iData || term->NewWidth || term->NewHeight)
472                         {
473                                 // Adjust for text mode
474                                 if( *iData == TERM_MODE_TEXT ) {
475                                         term->NewHeight *= giVT_CharHeight;
476                                         term->NewWidth *= giVT_CharWidth;
477                                 }
478                                 // Fill unchanged dimensions
479                                 if(term->NewHeight == 0)        term->NewHeight = term->Height;
480                                 if(term->NewWidth == 0) term->NewWidth = term->Width;
481                                 // Set new mode
482                                 VT_int_ChangeMode(term, *iData, term->NewWidth, term->NewHeight);
483                                 // Clear unapplied dimensions
484                                 term->NewWidth = 0;
485                                 term->NewHeight = 0;
486                         }
487                         
488                         // Update the screen dimensions
489                         if(Node->Inode == giVT_CurrentTerminal)
490                                 VT_SetTerminal( giVT_CurrentTerminal );
491                 }
492                 LEAVE('i', term->Mode);
493                 return term->Mode;
494         
495         // Get/set the terminal width
496         case TERM_IOCTL_WIDTH:
497                 if(Data != NULL) {
498                         if( CheckMem(Data, sizeof(int)) == 0 ) {
499                                 LEAVE('i', -1);
500                                 return -1;
501                         }
502                         term->NewWidth = *iData;
503                 }
504                 if( term->NewWidth )
505                         ret = term->NewWidth;
506                 else if( term->Mode == TERM_MODE_TEXT )
507                         ret = term->TextWidth;
508                 else
509                         ret = term->Width;
510                 LEAVE('i', ret);
511                 return ret;
512         
513         // Get/set the terminal height
514         case TERM_IOCTL_HEIGHT:
515                 if(Data != NULL) {
516                         if( CheckMem(Data, sizeof(int)) == 0 ) {
517                                 LEAVE('i', -1);
518                                 return -1;
519                         }
520                         term->NewHeight = *iData;
521                 }
522                 if( term->NewHeight )
523                         ret = term->NewHeight;
524                 else if( term->Mode == TERM_MODE_TEXT )
525                         ret = term->TextHeight;
526                 else
527                         ret = term->Height;
528                 LEAVE('i', ret);
529                 return ret;
530         
531         case TERM_IOCTL_FORCESHOW:
532                 Log_Log("VTerm", "Thread %i forced VTerm %i to be shown",
533                         Threads_GetTID(), (int)Node->Inode);
534                 VT_SetTerminal( Node->Inode );
535                 LEAVE('i', 1);
536                 return 1;
537         
538         case TERM_IOCTL_GETSETCURSOR:
539                 if(Data != NULL)
540                 {
541                         tVideo_IOCtl_Pos        *pos = Data;
542                         if( !CheckMem(Data, sizeof(*pos)) ) {
543                                 errno = -EINVAL;
544                                 LEAVE('i', -1);
545                                 return -1;
546                         }
547                 
548                         if( term->Mode == TERM_MODE_TEXT )
549                         {
550                                 if(term->Flags & VT_FLAG_ALTBUF)
551                                         term->AltWritePos = pos->x + pos->y * term->TextWidth;
552                                 else
553                                         term->WritePos = pos->x + pos->y * term->TextWidth + term->ViewPos;
554                                 VT_int_UpdateCursor(term, 0);
555                         }
556                         else
557                         {
558                                 term->VideoCursorX = pos->x;
559                                 term->VideoCursorY = pos->y;
560                                 VT_int_UpdateCursor(term, 1);
561                         }
562                 }
563                 ret = (term->Flags & VT_FLAG_ALTBUF) ? term->AltWritePos : term->WritePos-term->ViewPos;
564                 LEAVE('i', ret);
565                 return ret;
566
567         case TERM_IOCTL_SETCURSORBITMAP: {
568                 tVideo_IOCtl_Bitmap     *bmp = Data;
569                 if( Data == NULL )
570                 {
571                         free( term->VideoCursor );
572                         term->VideoCursor = NULL;
573                         LEAVE('i', 0);
574                         return 0;
575                 }
576
577                 // Sanity check bitmap
578                 if( !CheckMem(bmp, sizeof(tVideo_IOCtl_Bitmap)) ) {
579                         Log_Notice("VTerm", "%p in TERM_IOCTL_SETCURSORBITMAP invalid", bmp);
580                         errno = -EINVAL;
581                         LEAVE_RET('i', -1);
582                 }
583                 if( !CheckMem(bmp->Data, bmp->W*bmp->H*sizeof(Uint32)) ) {
584                         Log_Notice("VTerm", "%p in TERM_IOCTL_SETCURSORBITMAP invalid", bmp);
585                         errno = -EINVAL;
586                         LEAVE_RET('i', -1);
587                 }
588
589                 // Reallocate if needed
590                 if(term->VideoCursor)
591                 {
592                         if(bmp->W * bmp->H != term->VideoCursor->W * term->VideoCursor->H) {
593                                 free(term->VideoCursor);
594                                 term->VideoCursor = NULL;
595                         }
596                 }
597                 if(!term->VideoCursor) {
598                         term->VideoCursor = malloc(sizeof(tVideo_IOCtl_Pos) + bmp->W*bmp->H*sizeof(Uint32));
599                         if(!term->VideoCursor) {
600                                 Log_Error("VTerm", "Unable to allocate memory for cursor");
601                                 errno = -ENOMEM;
602                                 LEAVE_RET('i', -1);
603                         }
604                 }
605                 
606                 memcpy(term->VideoCursor, bmp, sizeof(tVideo_IOCtl_Pos) + bmp->W*bmp->H*sizeof(Uint32));
607         
608                 Log_Debug("VTerm", "Set VT%i's cursor to %p %ix%i",
609                         (int)term->Node.Inode, bmp, bmp->W, bmp->H);
610
611                 if(gpVT_CurTerm == term)
612                         VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSORBITMAP, term->VideoCursor);
613         
614                 LEAVE('i', 0);
615                 return 0; }
616         }
617         LEAVE('i', -1);
618         return -1;
619 }
620
621 void VT_Terminal_Reference(tVFS_Node *Node)
622 {
623         // Append PID to list
624 }
625
626 void VT_Terminal_Close(tVFS_Node *Node)
627 {
628         // Remove PID from list
629 }
630 #endif
631
632 /**
633  * \fn void VT_SetTerminal(int ID)
634  * \brief Set the current terminal
635  */
636 void VT_SetTerminal(int ID)
637 {
638         // Copy the screen state
639         if( ID != giVT_CurrentTerminal && gpVT_CurTerm->Mode != TERM_MODE_TEXT )
640         {
641                 if( !gpVT_CurTerm->Buffer )
642                         gpVT_CurTerm->Buffer = malloc( gpVT_CurTerm->Width*gpVT_CurTerm->Height*4 );
643                 if( gpVT_CurTerm->Width < giVT_RealWidth )
644                 {
645                         Uint    ofs = 0;
646                         Uint32  *dest = gpVT_CurTerm->Buffer;
647                         // Slower scanline copy
648                         for( int line = 0; line < gpVT_CurTerm->Height; line ++ )
649                         {
650                                 VFS_ReadAt(giVT_OutputDevHandle, ofs, gpVT_CurTerm->Width*4, dest);
651                                 ofs += giVT_RealWidth * 4;
652                                 dest += gpVT_CurTerm->Width;
653                         }
654                 }
655                 else
656                 {
657                         VFS_ReadAt(giVT_OutputDevHandle,
658                                 0, gpVT_CurTerm->Height*giVT_RealWidth*4,
659                                 gpVT_CurTerm->Buffer
660                                 );
661                 }
662                 LOG("Cached screen contents");
663         }
664
665         // Update current terminal ID
666         Log_Log("VTerm", "Changed terminal from %i to %i", giVT_CurrentTerminal, ID);
667         giVT_CurrentTerminal = ID;
668         gpVT_CurTerm = &gVT_Terminals[ID];
669         
670         LOG("Attempting VT_SetMode");
671         
672         if( gpVT_CurTerm->Mode == PTYBUFFMT_TEXT )
673         {
674                 VT_SetMode( VIDEO_BUFFMT_TEXT );
675         }
676         else
677         {
678                 // Update the cursor image
679                 if(gpVT_CurTerm->VideoCursor)
680                         VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSORBITMAP, gpVT_CurTerm->VideoCursor);
681                 VT_SetMode( VIDEO_BUFFMT_FRAMEBUFFER );
682         }
683
684         LOG("Mode set");        
685
686         if(gpVT_CurTerm->Buffer)
687         {
688                 // TODO: Handle non equal sized
689                 VFS_WriteAt(
690                         giVT_OutputDevHandle,
691                         0,
692                         gpVT_CurTerm->Width*gpVT_CurTerm->Height*sizeof(Uint32),
693                         gpVT_CurTerm->Buffer
694                         );
695                 LOG("Updated screen contents");
696         }
697         
698         VT_int_UpdateCursor(gpVT_CurTerm, 1);
699         // Update the screen
700         VT_int_UpdateScreen(gpVT_CurTerm, 1);
701         LOG("done");
702 }

UCC git Repository :: git.ucc.asn.au