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

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