X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;ds=sidebyside;f=KernelLand%2FKernel%2Fdrv%2Fvterm_2d.c;fp=KernelLand%2FKernel%2Fdrv%2Fvterm_2d.c;h=aadf7a2003c373911a1e6d31ae36b5699fd47b69;hb=a392d810ae1d5ef9779d232f48a8b7a3bba3c1b8;hp=0000000000000000000000000000000000000000;hpb=8b31abd0e78318f75f952e59a8c3b65eea41cb86;p=tpg%2Facess2.git diff --git a/KernelLand/Kernel/drv/vterm_2d.c b/KernelLand/Kernel/drv/vterm_2d.c new file mode 100644 index 00000000..aadf7a20 --- /dev/null +++ b/KernelLand/Kernel/drv/vterm_2d.c @@ -0,0 +1,243 @@ +/* + * Acess2 Kernel + * - By John Hodge (thePowersGang) + * + * drv/vterm_2d.c + * - 2D command processing + */ +#define DEBUG 0 +#include "vterm.h" +#include + +void VT_int_SetCursorPos(tVTerm *Term, int X, int Y); +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); + +// === CODE === +void VT_int_SetCursorPos(tVTerm *Term, int X, int Y) +{ + if( Term->Mode == PTYBUFFMT_TEXT ) + { + if(Term->Flags & VT_FLAG_ALTBUF) + Term->AltWritePos = X + Y * Term->TextWidth; + else + Term->WritePos = X + Y * Term->TextWidth + Term->ViewPos; + VT_int_UpdateCursor(Term, 0); + } + else + { + Term->VideoCursorX = X; + Term->VideoCursorY = Y; + VT_int_UpdateCursor(Term, 1); + } +} + +void VT_int_SetCursorBitmap(tVTerm *Term, int W, int H) +{ + LOG("WxH = %ix%i", W, H); + if(Term->VideoCursor) + { + if(W * H != Term->VideoCursor->W * Term->VideoCursor->H) { + free(Term->VideoCursor); + Term->VideoCursor = NULL; + } + } + if(!Term->VideoCursor) { + Term->VideoCursor = malloc(sizeof(*Term->VideoCursor) + W*H*sizeof(Uint32)); + if(!Term->VideoCursor) { + Log_Error("VTerm", "Unable to allocate memory for cursor"); + return ; + } + } + Term->VideoCursor->W = W; + Term->VideoCursor->H = H; +} + +size_t VT_int_FillCursorBitmap(tVTerm *Term, size_t DataOfs, size_t Length, const void *Data) +{ + if( !Term->VideoCursor ) + return 0; + size_t limit = Term->VideoCursor->W * Term->VideoCursor->H * 4; + if( DataOfs > limit ) + return 0; + if( Length > limit ) + Length = limit; + if( DataOfs + Length > limit ) + Length = limit - DataOfs; + + LOG("memcpy(VideoCursor->Data + 0x%x, Data, 0x%x)", DataOfs, Length); + memcpy((char*)Term->VideoCursor->Data + DataOfs, Data, Length); + + if(gpVT_CurTerm == Term) + VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSORBITMAP, Term->VideoCursor); + return Length; +} + +// --- 2D Command deserialising --- +int VT_int_2DCmd_SetCursorPos(void *Handle, size_t Offset, size_t Length, const void *Data) +{ + struct ptycmd_setcursorpos cmd; + if( Length < sizeof(cmd) ) return 0; + memcpy(&cmd, Data, sizeof(cmd)); + + VT_int_SetCursorPos(Handle, cmd.x, cmd.y); + + return sizeof(cmd); +} + +int VT_int_2DCmd_SetCursorBitmap(void *Handle, size_t Offset, size_t Length, const void *Data) +{ + struct ptycmd_setcursorbmp cmd; + tVTerm *term = Handle; + size_t ret = 0; + + if( Offset == 0 ) { + if( Length < sizeof(cmd) ) return 0; + memcpy(&cmd, Data, sizeof(cmd)); + VT_int_SetCursorBitmap(Handle, cmd.w, cmd.h); + ret = sizeof(cmd); + Length -= ret; + Data = (const char*)Data + ret; + Offset += ret; + if( Length == 0 ) + return -ret; + } + + + if( Offset < sizeof(cmd) ) { + // oops? + return ret; + } + + 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; + + return -ret; +} + +// > 0: Command complete +// = 0: Not enough data to start +// < 0: Ate -n bytes, still need more +typedef int (*tVT_2DCmdHandler)(void *Handle, size_t Offset, size_t Length, const void *Data); +tVT_2DCmdHandler gVT_2DCmdHandlers[] = { + [PTY2D_CMD_SETCURSORPOS] = VT_int_2DCmd_SetCursorPos, + [PTY2D_CMD_SETCURSORBMP] = VT_int_2DCmd_SetCursorBitmap, +}; +const int ciVT_Num2DCmdHandlers = sizeof(gVT_2DCmdHandlers)/sizeof(gVT_2DCmdHandlers[0]); + +void VT_int_Handle2DCmd(void *Handle, size_t Length, const void *Data) +{ + const uint8_t *bdata = Data; + tVTerm *term = Handle; + + LOG("Length = 0x%x", Length); + // If a command terminated early, we have to clean up its data +_eat: + if( term->Cmd2D.PreEat ) + { + size_t nom = MIN(term->Cmd2D.PreEat, Length); + bdata += nom; + Length -= nom; + LOG("Discarding %i/%i ignored bytes of input", nom, term->Cmd2D.PreEat); + term->Cmd2D.PreEat -= nom; + } + + while( Length > 0 ) + { + const int cachesize = sizeof(term->Cmd2D.Cache); + size_t len, adjust; + const void *dataptr; + + // Check for command resume + if( term->Cmd2D.Current ) + { + LOG("Resuming %i at +0x%x with 0x%x", term->Cmd2D.Current, term->Cmd2D.Offset, Length); + dataptr = (void*)bdata; + len = Length; + adjust = 0; + } + // else begin a new command + else + { + if( Length < cachesize || term->Cmd2D.CachePos != 0 ) + { + adjust = term->Cmd2D.CachePos; + size_t newbytes = MIN(cachesize - term->Cmd2D.CachePos, Length); + memcpy(term->Cmd2D.Cache + term->Cmd2D.CachePos, bdata, newbytes); + term->Cmd2D.CachePos += newbytes; + dataptr = (void*)term->Cmd2D.Cache; + len = term->Cmd2D.CachePos; + } + else { + dataptr = (void*)bdata; + len = Length; + adjust = 0; + } + const struct ptycmd_header *hdr = dataptr; + + if( len < sizeof(*hdr) ) { + return ; + } + + 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 ) + term->Cmd2D.CurrentSize = 2; + LOG("Started %i with %s data", + term->Cmd2D.Current, (dataptr == bdata ? "direct" : "cache")); + } + if( term->Cmd2D.Current >= ciVT_Num2DCmdHandlers || !gVT_2DCmdHandlers[term->Cmd2D.Current] ) + { + Log_Notice("VTerm", "2D Comand %i not handled", term->Cmd2D.Current); + if( Length < term->Cmd2D.CurrentSize ) + break; + term->Cmd2D.CachePos = 0; + term->Cmd2D.Current = 0; + term->Cmd2D.PreEat = term->Cmd2D.CurrentSize; + goto _eat; + } + else + { + 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 + 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); + term->Cmd2D.Current = 0; + + // 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); + } + } +}