3994525f66b34efc37212fc95e13d92362573133
[tpg/acess2.git] / KernelLand / Kernel / drv / vterm_2d.c
1 /*
2  * Acess2 Kernel
3  * - By John Hodge (thePowersGang)
4  *
5  * drv/vterm_2d.c
6  * - 2D command processing
7  */
8 #define DEBUG   0
9 #include "vterm.h"
10 #include <acess/devices/pty_cmds.h>
11
12 void    VT_int_SetCursorPos(tVTerm *Term, int X, int Y);
13 void    VT_int_SetCursorBitmap(tVTerm *Term, int W, int H);
14 size_t  VT_int_FillCursorBitmap(tVTerm *Term, size_t DataOfs, size_t Length, const void *Data);
15  int    VT_int_2DCmd_SetCursorPos(void *Handle, size_t Offset, size_t Length, const void *Data);
16  int    VT_int_2DCmd_SetCursorBitmap(void *Handle, size_t Offset, size_t Length, const void *Data);
17
18 // === CODE ===
19 void VT_int_SetCursorPos(tVTerm *Term, int X, int Y)
20 {
21         if( Term->Mode == PTYBUFFMT_TEXT )
22         {
23                 if(Term->Flags & VT_FLAG_ALTBUF)
24                         Term->AltWritePos = X + Y * Term->TextWidth;
25                 else
26                         Term->WritePos = X + Y * Term->TextWidth + Term->ViewPos;
27                 VT_int_UpdateCursor(Term, 0);
28         }
29         else
30         {
31                 Term->VideoCursorX = X;
32                 Term->VideoCursorY = Y;
33                 VT_int_UpdateCursor(Term, 1);
34         }
35 }
36
37 void VT_int_SetCursorBitmap(tVTerm *Term, int W, int H)
38 {
39         LOG("WxH = %ix%i", W, H);
40         if(Term->VideoCursor)
41         {
42                 if(W * H != Term->VideoCursor->W * Term->VideoCursor->H) {
43                         free(Term->VideoCursor);
44                         Term->VideoCursor = NULL;
45                 }
46         }
47         if(!Term->VideoCursor) {
48                 Term->VideoCursor = malloc(sizeof(*Term->VideoCursor) + W*H*sizeof(Uint32));
49                 if(!Term->VideoCursor) {
50                         Log_Error("VTerm", "Unable to allocate memory for cursor");
51                         return ;
52                 }
53         }
54         Term->VideoCursor->W = W;
55         Term->VideoCursor->H = H;
56         Term->VideoCursor->XOfs = 0;
57         Term->VideoCursor->YOfs = 0;
58 }
59
60 size_t VT_int_FillCursorBitmap(tVTerm *Term, size_t DataOfs, size_t Length, const void *Data)
61 {
62         if( !Term->VideoCursor )
63                 return 0;
64         size_t  limit = Term->VideoCursor->W * Term->VideoCursor->H * 4;
65         if( DataOfs > limit )
66                 return 0;
67         if( Length > limit )
68                 Length = limit;
69         if( DataOfs + Length > limit )
70                 Length = limit - DataOfs;
71         
72         LOG("memcpy(VideoCursor->Data + 0x%x, Data, 0x%x)", DataOfs, Length);
73         memcpy((char*)Term->VideoCursor->Data + DataOfs, Data, Length);
74         
75         if(gpVT_CurTerm == Term)
76                 VFS_IOCtl(giVT_OutputDevHandle, VIDEO_IOCTL_SETCURSORBITMAP, Term->VideoCursor);
77         return Length;
78 }
79
80 // --- 2D Command deserialising ---
81 int VT_int_2DCmd_SetCursorPos(void *Handle, size_t Offset, size_t Length, const void *Data)
82 {
83         struct ptycmd_setcursorpos      cmd;
84         if( Length < sizeof(cmd) )      return 0;
85         memcpy(&cmd, Data, sizeof(cmd));
86
87         VT_int_SetCursorPos(Handle, cmd.x, cmd.y);
88         
89         return sizeof(cmd);
90 }
91
92 int VT_int_2DCmd_SetCursorBitmap(void *Handle, size_t Offset, size_t Length, const void *Data)
93 {
94         struct ptycmd_setcursorbmp      cmd;
95         tVTerm  *term = Handle;
96         size_t  ret = 0;
97
98         if( Offset == 0 ) {
99                 if( Length < sizeof(cmd) )      return 0;
100                 memcpy(&cmd, Data, sizeof(cmd));
101                 VT_int_SetCursorBitmap(Handle, cmd.w, cmd.h);
102                 ret = sizeof(cmd);
103                 Length -= ret;
104                 Data = (const char*)Data + ret;
105                 Offset += ret;
106                 if( Length == 0 )
107                         return -ret;
108         }
109
110
111         if( Offset < sizeof(cmd) ) {
112                 // oops?
113                 return ret;
114         }
115
116         ret += VT_int_FillCursorBitmap(Handle, Offset - sizeof(cmd), Length, Data);
117
118         LOG("%i + %i ==? %i", ret, Offset, term->Cmd2D.CurrentSize);
119         if( ret + Offset >= term->Cmd2D.CurrentSize )
120                 return ret;
121
122         return -ret;
123 }
124
125 // > 0: Command complete
126 // = 0: Not enough data to start
127 // < 0: Ate -n bytes, still need more
128 typedef int     (*tVT_2DCmdHandler)(void *Handle, size_t Offset, size_t Length, const void *Data);
129 tVT_2DCmdHandler        gVT_2DCmdHandlers[] = {
130         [PTY2D_CMD_SETCURSORPOS] = VT_int_2DCmd_SetCursorPos,
131         [PTY2D_CMD_SETCURSORBMP] = VT_int_2DCmd_SetCursorBitmap,
132 };
133 const int       ciVT_Num2DCmdHandlers = sizeof(gVT_2DCmdHandlers)/sizeof(gVT_2DCmdHandlers[0]);
134
135 void VT_int_Handle2DCmd(void *Handle, size_t Length, const void *Data)
136 {
137         const uint8_t   *bdata = Data;
138         tVTerm  *term = Handle;
139
140         LOG("Length = 0x%x", Length);
141         // If a command terminated early, we have to clean up its data
142 _eat:
143         if( term->Cmd2D.PreEat )
144         {
145                 size_t  nom = MIN(term->Cmd2D.PreEat, Length);
146                 bdata += nom;
147                 Length -= nom;
148                 LOG("Discarding %i/%i ignored bytes of input", nom, term->Cmd2D.PreEat);
149                 term->Cmd2D.PreEat -= nom;
150         }
151
152         while( Length > 0 )
153         {
154                 const int cachesize = sizeof(term->Cmd2D.Cache);
155                 size_t  len, adjust;
156                 const void      *dataptr;
157         
158                 // Check for command resume
159                 if( term->Cmd2D.Current )
160                 {
161                         LOG("Resuming %i at +0x%x with 0x%x", term->Cmd2D.Current, term->Cmd2D.Offset, Length);
162                         dataptr = (void*)bdata;
163                         len = Length;
164                         adjust = 0;
165                 }
166                 // else begin a new command
167                 else
168                 {               
169                         if( Length < cachesize || term->Cmd2D.CachePos != 0 )
170                         {
171                                 adjust = term->Cmd2D.CachePos;
172                                 size_t newbytes = MIN(cachesize - term->Cmd2D.CachePos, Length);
173                                 memcpy(term->Cmd2D.Cache + term->Cmd2D.CachePos, bdata, newbytes);
174                                 term->Cmd2D.CachePos += newbytes;
175                                 dataptr = (void*)term->Cmd2D.Cache;
176                                 len = term->Cmd2D.CachePos;
177                         }
178                         else {
179                                 dataptr = (void*)bdata;
180                                 len = Length;
181                                 adjust = 0;
182                         }
183                         const struct ptycmd_header      *hdr = dataptr;
184
185                         if( len < sizeof(*hdr) ) {
186                                 return ;
187                         }                       
188
189                         term->Cmd2D.Offset = 0;
190                         term->Cmd2D.Current = hdr->cmd;
191                         term->Cmd2D.CurrentSize = (hdr->len_low | (hdr->len_hi << 8)) * 4;
192                         if( term->Cmd2D.CurrentSize == 0 )
193                                 term->Cmd2D.CurrentSize = 2;
194                         LOG("Started %i with %s data",
195                                 term->Cmd2D.Current, (dataptr == bdata ? "direct" : "cache"));
196                 }
197                 if( term->Cmd2D.Current >= ciVT_Num2DCmdHandlers || !gVT_2DCmdHandlers[term->Cmd2D.Current] )
198                 {
199                         Log_Notice("VTerm", "2D Comand %i not handled", term->Cmd2D.Current);
200                         if( Length < term->Cmd2D.CurrentSize )
201                                 break;
202                         term->Cmd2D.CachePos = 0;
203                         term->Cmd2D.Current = 0;
204                         term->Cmd2D.PreEat = term->Cmd2D.CurrentSize;
205                         goto _eat;
206                 }
207                 else
208                 {
209                         int rv = gVT_2DCmdHandlers[term->Cmd2D.Current](Handle, term->Cmd2D.Offset, len, dataptr);
210                         LOG("2DCmd %i: rv=%i", term->Cmd2D.Current, rv);
211                         if( rv == 0 && term->Cmd2D.Offset == 0 ) {
212                                 // 0: Not enough data for header
213                                 ASSERT( term->Cmd2D.CachePos != cachesize );
214                                 // Clear current command because this command hasn't started yet
215                                 term->Cmd2D.Current = 0;
216                                 // Return, restart happens once all data is ready
217                                 return ;
218                         }
219                         size_t used_bytes = (rv < 0 ? -rv : rv) - adjust;
220                         Length -= used_bytes;
221                         bdata += used_bytes;
222                         term->Cmd2D.CachePos = 0;
223                         if( rv < 0 ) {
224                                 ASSERT( -rv <= len );
225                                 LOG(" Incomplete");
226                                 term->Cmd2D.Offset += -rv;
227                                 continue ;
228                         }
229                         ASSERT(rv <= len);
230                         term->Cmd2D.Current = 0;
231
232                         // Eat up any uneaten data
233                         // - TODO: Need to eat across writes
234                         ASSERT( term->Cmd2D.Offset + rv <= term->Cmd2D.CurrentSize );
235                         if( term->Cmd2D.Offset + rv < term->Cmd2D.CurrentSize )
236                         {
237                                 size_t  diff = term->Cmd2D.CurrentSize - (term->Cmd2D.Offset + rv);
238                                 LOG("Left %i bytes", diff);
239                                 term->Cmd2D.PreEat = diff;
240                                 goto _eat;
241                         }
242                         LOG("Done (%i bytes left)", Length);
243                 }
244         }
245 }

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