Kernel/VTerm - Add 2DCmd push image support
authorJohn Hodge <[email protected]>
Sun, 8 Jun 2014 13:20:11 +0000 (21:20 +0800)
committerJohn Hodge <[email protected]>
Sun, 8 Jun 2014 13:20:11 +0000 (21:20 +0800)
KernelLand/Kernel/drv/vterm.c
KernelLand/Kernel/drv/vterm.h
KernelLand/Kernel/drv/vterm_2d.c

index 2c6a0d2..2175570 100644 (file)
@@ -5,7 +5,7 @@
  * drv/vterm.c
  * - Virtual Terminal - Initialisation and VFS Interface
  */
-#define DEBUG  1
+#define DEBUG  0
 #include "vterm.h"
 #include <fs_devfs.h>
 #include <modules.h>
@@ -34,7 +34,6 @@ extern void   Debug_SetKTerminal(const char *File);
 // === PROTOTYPES ===
  int   VT_Install(char **Arguments);
  int   VT_Root_IOCtl(tVFS_Node *Node, int Id, void *Data);
-void   VT_int_PutFBData(tVTerm *Term, size_t Offset, size_t Length, const 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);
@@ -369,15 +368,16 @@ void VT_PTYOutput(void *Handle, size_t Length, const void *Data)
                VT_int_PutString(term, Data, Length);
                break;
        case PTYBUFFMT_FB:
-               // TODO: How do offset?
+               // 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:
-               // TODO: Impliment 2D commands
                VT_int_Handle2DCmd(term, Length, Data);
                break;
        case PTYBUFFMT_3DCMD:
-               // TODO: Impliment 3D commands
+               // TODO: Implement 3D commands
+               Warning("TODO: VTerm 3D commands");
                break;
        }
 }
index 05aad87..75128ba 100644 (file)
@@ -94,6 +94,11 @@ struct sVTerm
                 int    CachePos;
                char    Cache[32];
                size_t  PreEat;
+               union {
+                       struct {
+                               size_t  Offset;
+                       } Push;
+               } CmdInfo;
        } Cmd2D;
 
        tPTY    *PTY;
@@ -134,6 +139,7 @@ extern void VT_int_ClearLine(tVTerm *Term, int Num);
 extern void    VT_int_ClearInLine(tVTerm *Term, int Row, int FirstCol, int LastCol);
 extern void    VT_int_Resize(tVTerm *Term, int NewWidth, int NewHeight);
 extern void    VT_int_ToggleAltBuffer(tVTerm *Term, int Enabled);
+extern void    VT_int_PutFBData(tVTerm *Term, size_t Offset, size_t Length, const void *Buffer);
 
 extern tVT_Pos *VT_int_GetWritePosPtr(tVTerm *Term);
 extern size_t  VT_int_GetBufferRows(tVTerm *Term);
index 4b750ab..086c2b4 100644 (file)
@@ -14,6 +14,7 @@ void  VT_int_SetCursorBitmap(tVTerm *Term, int W, int H);
 size_t VT_int_FillCursorBitmap(tVTerm *Term, size_t DataOfs, size_t Length, const void *Data);
  int   VT_int_2DCmd_SetCursorPos(void *Handle, size_t Offset, size_t Length, const void *Data);
  int   VT_int_2DCmd_SetCursorBitmap(void *Handle, size_t Offset, size_t Length, const void *Data);
+ int   VT_int_2DCmd_SendData(void *Handle, size_t Offset, size_t Length, const void *Data);
 
 // === CODE ===
 void VT_int_SetCursorPos(tVTerm *Term, int X, int Y)
@@ -102,18 +103,15 @@ int VT_int_2DCmd_SetCursorBitmap(void *Handle, size_t Offset, size_t Length, con
                Length -= ret;
                Data = (const char*)Data + ret;
                Offset += ret;
-               if( Length == 0 )
-                       return -ret;
        }
+       
+       ASSERTC(Offset, >=, sizeof(cmd));
 
-
-       if( Offset < sizeof(cmd) ) {
-               // oops?
-               return ret;
+       if( Length > 0 )
+       {
+               ret += VT_int_FillCursorBitmap(Handle, Offset - sizeof(cmd), Length, Data);
        }
 
-       ret += VT_int_FillCursorBitmap(Handle, Offset - sizeof(cmd), Length, Data);
-
        LOG("%i + %i ==? %i", ret, Offset, term->Cmd2D.CurrentSize);
        if( ret + Offset >= term->Cmd2D.CurrentSize )
                return ret;
@@ -121,6 +119,46 @@ int VT_int_2DCmd_SetCursorBitmap(void *Handle, size_t Offset, size_t Length, con
        return -ret;
 }
 
+int VT_int_2DCmd_SendData(void *Handle, size_t Offset, size_t Length, const void *Data)
+{
+       tVTerm  *term = Handle;
+       struct ptycmd_senddata  cmd;
+       size_t  ret = 0;
+       
+       if( Offset == 0 )
+       {
+               if( Length < sizeof(cmd) )
+                       return 0;
+               memcpy(&cmd, Data, sizeof(cmd));
+               
+               ret = sizeof(cmd);
+               Offset += ret;
+               Length -= ret;
+               Data = (const char*)Data + ret;
+               
+               term->Cmd2D.CmdInfo.Push.Offset = cmd.ofs*4;
+       }
+       
+       ASSERTC(Offset, >=, sizeof(cmd));
+       
+       if( Length > 0 )
+       {
+               size_t  bytes = MIN(term->Width*term->Height*4 - term->Cmd2D.CmdInfo.Push.Offset, Length);
+               LOG("bytes = %i (0x%x), Length = %i", bytes, bytes, Length);
+               
+               VT_int_PutFBData(term, term->Cmd2D.CmdInfo.Push.Offset, bytes, Data );
+               term->Cmd2D.CmdInfo.Push.Offset += bytes;
+               ret += bytes;
+               
+               LOG("bytes(%i) ==? 0 || ret(%i) + Offset(%i) ==? %i",
+                       bytes, ret, Offset, term->Cmd2D.CurrentSize);
+               if( bytes == 0 || ret + Offset >= term->Cmd2D.CurrentSize )
+                       return ret;
+       }
+       
+       return -ret;
+}
+
 // > 0: Command complete
 // = 0: Not enough data to start
 // < 0: Ate -n bytes, still need more
@@ -128,6 +166,7 @@ typedef int (*tVT_2DCmdHandler)(void *Handle, size_t Offset, size_t Length, cons
 tVT_2DCmdHandler       gVT_2DCmdHandlers[] = {
        [PTY2D_CMD_SETCURSORPOS] = VT_int_2DCmd_SetCursorPos,
        [PTY2D_CMD_SETCURSORBMP] = VT_int_2DCmd_SetCursorBitmap,
+       [PTY2D_CMD_SEND] = VT_int_2DCmd_SendData,
 };
 const int      ciVT_Num2DCmdHandlers = sizeof(gVT_2DCmdHandlers)/sizeof(gVT_2DCmdHandlers[0]);
 
@@ -137,7 +176,7 @@ void VT_int_Handle2DCmd(void *Handle, size_t Length, const void *Data)
        tVTerm  *term = Handle;
 
        LOG("Length = 0x%x", Length);
-       // If a command terminated early, we have to clean up its data
+       // If a command didn't consume all the data it said it would, we have to clean up
 _eat:
        if( term->Cmd2D.PreEat )
        {
@@ -164,7 +203,10 @@ _eat:
                }
                // else begin a new command
                else
-               {               
+               {
+                       // If the new data would fit in the cache, or the cache is already populated
+                       // use the cache
+                       // - The cache should fit the header for every command, so all good
                        if( Length < cachesize || term->Cmd2D.CachePos != 0 )
                        {
                                adjust = term->Cmd2D.CachePos;
@@ -174,25 +216,33 @@ _eat:
                                dataptr = (void*)term->Cmd2D.Cache;
                                len = term->Cmd2D.CachePos;
                        }
-                       else {
+                       else
+                       {
                                dataptr = (void*)bdata;
                                len = Length;
                                adjust = 0;
                        }
                        const struct ptycmd_header      *hdr = dataptr;
 
-                       if( len < sizeof(*hdr) ) {
+                       // If there's not enough for the common header, wait for more
+                       if( len < sizeof(*hdr) )
+                       {
                                return ;
                        }                       
 
+                       // Parse header
                        term->Cmd2D.Offset = 0;
                        term->Cmd2D.Current = hdr->cmd;
                        term->Cmd2D.CurrentSize = (hdr->len_low | (hdr->len_hi << 8)) * 4;
-                       if( term->Cmd2D.CurrentSize == 0 )
+                       if( term->Cmd2D.CurrentSize == 0 ) {
+                               Log_Warning("VTerm", "Command size too small (==0)");
                                term->Cmd2D.CurrentSize = 2;
+                       }
                        LOG("Started %i with %s data",
                                term->Cmd2D.Current, (dataptr == bdata ? "direct" : "cache"));
                }
+
+               // Sanity check
                if( term->Cmd2D.Current >= ciVT_Num2DCmdHandlers || !gVT_2DCmdHandlers[term->Cmd2D.Current] )
                {
                        Log_Notice("VTerm", "2D Comand %i not handled", term->Cmd2D.Current);
@@ -203,42 +253,60 @@ _eat:
                        term->Cmd2D.PreEat = term->Cmd2D.CurrentSize;
                        goto _eat;
                }
-               else
+               
+               const tVT_2DCmdHandler* handler = &gVT_2DCmdHandlers[term->Cmd2D.Current];
+               #if 0
+               if( term->Cmd2D.Offset == 0 )
                {
-                       int rv = gVT_2DCmdHandlers[term->Cmd2D.Current](Handle, term->Cmd2D.Offset, len, dataptr);
-                       LOG("2DCmd %i: rv=%i", term->Cmd2D.Current, rv);
-                       if( rv == 0 && term->Cmd2D.Offset == 0 ) {
-                               // 0: Not enough data for header
-                               ASSERT( term->Cmd2D.CachePos != cachesize );
-                               // Clear current command because this command hasn't started yet
-                               term->Cmd2D.Current = 0;
-                               // Return, restart happens once all data is ready
+                       if( len < handler->HeaderLength ) {
                                return ;
                        }
-                       size_t used_bytes = (rv < 0 ? -rv : rv) - adjust;
-                       Length -= used_bytes;
-                       bdata += used_bytes;
-                       term->Cmd2D.CachePos = 0;
-                       if( rv < 0 ) {
-                               ASSERT( -rv <= len );
-                               LOG(" Incomplete");
-                               term->Cmd2D.Offset += -rv;
-                               continue ;
-                       }
-                       ASSERT(rv <= len);
+                       rv = handler->Header(Handle, len, dataptr);
+               }
+               else
+               {
+                       rv = hander->Body(Handle, term->Cmd2D.Offset, len, dataptr);
+               }
+               #endif
+               
+               // Call Handler 
+               int rv = (*handler)(Handle, term->Cmd2D.Offset, len, dataptr);
+               LOG("2DCmd %i: rv=%i", term->Cmd2D.Current, rv);
+               
+               // If it returned 0 on the first call, it lacks space for the header
+               if( rv == 0 && term->Cmd2D.Offset == 0 )
+               {
+                       ASSERT( term->Cmd2D.CachePos != cachesize );
+                       // Clear current command because this command hasn't started yet
                        term->Cmd2D.Current = 0;
+                       // Return, restart happens once all data is ready
+                       return ;
+               }
 
-                       // Eat up any uneaten data
-                       // - TODO: Need to eat across writes
-                       ASSERT( term->Cmd2D.Offset + rv <= term->Cmd2D.CurrentSize );
-                       if( term->Cmd2D.Offset + rv < term->Cmd2D.CurrentSize )
-                       {
-                               size_t  diff = term->Cmd2D.CurrentSize - (term->Cmd2D.Offset + rv);
-                               LOG("Left %i bytes", diff);
-                               term->Cmd2D.PreEat = diff;
-                               goto _eat;
-                       }
-                       LOG("Done (%i bytes left)", Length);
+               // Consume the byte count returned (adjust is the number of bytes that were already cached)
+               size_t used_bytes = (rv < 0 ? -rv : rv) - adjust;
+               Length -= used_bytes;
+               bdata += used_bytes;
+               term->Cmd2D.CachePos = 0;
+               // If a negative count was returned, more data is expected
+               if( rv < 0 ) {
+                       ASSERT( -rv <= len );
+                       LOG(" Incomplete");
+                       term->Cmd2D.Offset += -rv;
+                       continue ;
+               }
+               ASSERT(rv <= len);
+               term->Cmd2D.Current = 0;
+
+               // Eat up any uneaten data
+               ASSERT( term->Cmd2D.Offset + rv <= term->Cmd2D.CurrentSize );
+               if( term->Cmd2D.Offset + rv < term->Cmd2D.CurrentSize )
+               {
+                       size_t  diff = term->Cmd2D.CurrentSize - (term->Cmd2D.Offset + rv);
+                       LOG("Left %i bytes", diff);
+                       term->Cmd2D.PreEat = diff;
+                       goto _eat;
                }
+               LOG("Done (%i bytes left)", Length);
        }
 }

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