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

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