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

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