Kernel - Update VFS API to use off_t/size_t instead of Uint64
[tpg/acess2.git] / KernelLand / Modules / x86 / VGAText / vga.c
1 /*
2  * Acess2 VGA Controller Driver
3  */
4 #define DEBUG   0
5 #include <acess.h>
6 #include <fs_devfs.h>
7 #include <api_drv_video.h>
8 #include <modules.h>
9
10 // === CONSTANTS ===
11 #define VGA_WIDTH       80
12 #define VGA_HEIGHT      25
13
14 // === PROTOTYPES ===
15  int    VGA_Install(char **Arguments);
16 size_t  VGA_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer);
17  int    VGA_IOCtl(tVFS_Node *Node, int Id, void *Data);
18 Uint8   VGA_int_GetColourNibble(Uint16 col);
19 Uint16  VGA_int_GetWord(const tVT_Char *Char);
20 void    VGA_int_SetCursor(Sint16 x, Sint16 y);
21 // --- 2D Acceleration Functions --
22 void    VGA_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour);
23 void    VGA_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H);
24
25 // === GLOBALS ===
26 MODULE_DEFINE(0, 0x000A, x86_VGAText, VGA_Install, NULL, NULL);
27 tVFS_NodeType   gVGA_NodeType = {
28         //.Read = VGA_Read,
29         .Write = VGA_Write,
30         .IOCtl = VGA_IOCtl
31         };
32 tDevFS_Driver   gVGA_DevInfo = {
33         NULL, "x86_VGAText",
34         {
35         .NumACLs = 0,
36         .Size = VGA_WIDTH*VGA_HEIGHT*sizeof(tVT_Char),
37         .Type = &gVGA_NodeType
38         }
39 };
40 Uint16  *gVGA_Framebuffer = (void*)( KERNEL_BASE|0xB8000 );
41  int    giVGA_BufferFormat = VIDEO_BUFFMT_TEXT;
42 tDrvUtil_Video_2DHandlers       gVGA_2DFunctions = {
43         NULL,
44         VGA_2D_Fill,
45         VGA_2D_Blit
46 };
47
48 // === CODE ===
49 /**
50  * \fn int VGA_Install(char **Arguments)
51  */
52 int VGA_Install(char **Arguments)
53 {
54         Uint8   byte;
55         
56         // Enable Bright Backgrounds
57         inb(0x3DA);     // Reset flipflop
58         outb(0x3C0, 0x30);      // Index 0x10, PAS
59         byte = inb(0x3C1);
60         byte &= ~8;     // Disable Blink
61         outb(0x3C0, byte);      // Write value
62         
63         
64         // Install DevFS
65         DevFS_AddDevice( &gVGA_DevInfo );
66         
67         return MODULE_ERR_OK;
68 }
69
70 /**
71  * \brief Writes a string of bytes to the VGA controller
72  */
73 size_t VGA_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer)
74 {
75         if( giVGA_BufferFormat == VIDEO_BUFFMT_TEXT )
76         {
77                  int    num = Length / sizeof(tVT_Char);
78                  int    ofs = Offset / sizeof(tVT_Char);
79                  int    i = 0;
80                 const tVT_Char  *chars = Buffer;
81                 Uint16  word;
82                 
83                 //ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
84                 
85                 for( ; num--; i ++, ofs ++)
86                 {
87                         word = VGA_int_GetWord( &chars[i] );
88                         gVGA_Framebuffer[ ofs ] = word;
89                 }
90                 
91                 //LEAVE('X', Length);
92                 return Length;
93         }
94         else if( giVGA_BufferFormat == VIDEO_BUFFMT_2DSTREAM )
95         {
96                 return DrvUtil_Video_2DStream(NULL, Buffer, Length, &gVGA_2DFunctions, sizeof(gVGA_2DFunctions));
97         }
98         else
99         {
100                 return 0;
101         }
102 }
103
104 /**
105  * \fn int VGA_IOCtl(tVFS_Node *Node, int Id, void *Data)
106  * \brief IO Control Call
107  */
108 int VGA_IOCtl(tVFS_Node *Node, int ID, void *Data)
109 {
110          int    rv;
111         switch(ID)
112         {
113         case DRV_IOCTL_TYPE:    return DRV_TYPE_VIDEO;
114         case DRV_IOCTL_IDENT:   memcpy(Data, "VGA\0", 4);       return 1;
115         case DRV_IOCTL_VERSION: *(int*)Data = 50;       return 1;
116         case DRV_IOCTL_LOOKUP:  return 0;
117         
118         case VIDEO_IOCTL_GETSETMODE:    return 0;       // Mode 0 only
119         case VIDEO_IOCTL_FINDMODE:
120                 if( !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)) )        return -1;
121                 ((tVideo_IOCtl_Mode*)Data)->id = 0;     // Text Only!
122         case VIDEO_IOCTL_MODEINFO:
123                 if( !CheckMem(Data, sizeof(tVideo_IOCtl_Mode)) )        return -1;
124                 if( ((tVideo_IOCtl_Mode*)Data)->id != 0)        return 0;
125                 ((tVideo_IOCtl_Mode*)Data)->width = VGA_WIDTH*giVT_CharWidth;
126                 ((tVideo_IOCtl_Mode*)Data)->height = VGA_HEIGHT*giVT_CharHeight;
127                 ((tVideo_IOCtl_Mode*)Data)->bpp = 4;
128                 return 1;
129         
130         case VIDEO_IOCTL_SETBUFFORMAT:
131                 if( !CheckMem(Data, sizeof(int)) )      return -1;
132                 switch( *(int*)Data )
133                 {
134                 case VIDEO_BUFFMT_TEXT:
135                 case VIDEO_BUFFMT_2DSTREAM:
136                         rv = giVGA_BufferFormat;
137                         giVGA_BufferFormat = *(int*)Data;
138 //                      Log_Debug("VGA", "Buffer format set to %i", giVGA_BufferFormat);
139                         return rv;
140                 default:
141                         break;
142                 }
143                 return -1;
144         
145         case VIDEO_IOCTL_SETCURSOR:
146                 VGA_int_SetCursor( ((tVideo_IOCtl_Pos*)Data)->x, ((tVideo_IOCtl_Pos*)Data)->y );
147                 return 1;
148         }
149         return 0;
150 }
151
152 /**
153  * \fn Uint8 VGA_int_GetColourNibble(Uint16 col)
154  * \brief Converts a 12-bit colour into a VGA 4-bit colour
155  */
156 Uint8 VGA_int_GetColourNibble(Uint16 col)
157 {
158         Uint8   ret = 0;
159          int    bright = 0;
160         
161         col = col & 0xCCC;
162         col = ((col>>2)&3) | ((col>>4)&0xC) | ((col>>6)&0x30);
163         bright = ( (col & 2 ? 1 : 0) + (col & 8 ? 1 : 0) + (col & 32 ? 1 : 0) ) / 2;
164         
165         switch(col)
166         {
167         //      Black
168         case 0x00:      ret = 0x0;      break;
169         // Dark Grey
170         case 0x15:      ret = 0x8;      break;
171         // Blues
172         case 0x01:
173         case 0x02:      ret = 0x1;      break;
174         case 0x03:      ret = 0x9;      break;
175         // Green
176         case 0x04:
177         case 0x08:      ret = 0x2;      break;
178         case 0x0C:      ret = 0xA;      break;
179         // Reds
180         case 0x10:
181         case 0x20:      ret = 0x4;      break;
182         case 0x30:      ret = 0xC;      break;
183         // Light Grey
184         case 0x2A:      ret = 0x7;      break;
185         // White
186         case 0x3F:      ret = 0xF;      break;
187         
188         default:
189                 ret |= (col & 0x03 ? 1 : 0);
190                 ret |= (col & 0x0C ? 2 : 0);
191                 ret |= (col & 0x30 ? 4 : 0);
192                 ret |= (bright ? 8 : 0);
193                 break;
194         }
195         return ret;
196 }
197
198 /**
199  * \fn Uint16 VGA_int_GetWord(tVT_Char *Char)
200  * \brief Convers a character structure to a VGA character word
201  */
202 Uint16 VGA_int_GetWord(const tVT_Char *Char)
203 {
204         Uint16  ret;
205         Uint16  col;
206         
207         // Get Character
208         if(Char->Ch < 128)
209                 ret = Char->Ch;
210         else {
211                 switch(Char->Ch)
212                 {
213                 default:        ret = 0;        break;
214                 }
215         }
216         
217         col = VGA_int_GetColourNibble(Char->BGCol);
218         ret |= col << 12;
219         
220         col = VGA_int_GetColourNibble(Char->FGCol);
221         ret |= col << 8;
222         
223         return ret;
224 }
225
226 /**
227  * \fn void VGA_int_SetCursor(Sint16 x, Sint16 y)
228  * \brief Updates the cursor position
229  */
230 void VGA_int_SetCursor(Sint16 x, Sint16 y)
231 {
232          int    pos = x+y*VGA_WIDTH;
233         if(x == -1 || y == -1)
234                 pos = -1;
235         outb(0x3D4, 14);
236         outb(0x3D5, pos >> 8);
237         outb(0x3D4, 15);
238         outb(0x3D5, pos);
239 }
240
241 void VGA_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour)
242 {
243         tVT_Char        ch;
244         Uint16  word, *buf;
245
246         X /= giVT_CharWidth;
247         W /= giVT_CharWidth;
248         Y /= giVT_CharHeight;
249         H /= giVT_CharHeight;
250
251         ch.Ch = 0x20;
252         ch.BGCol  = (Colour & 0x0F0000) >> (16-8);
253         ch.BGCol |= (Colour & 0x000F00) >> (8-4);
254         ch.BGCol |= (Colour & 0x00000F);
255         word = VGA_int_GetWord(&ch);
256
257         Log("Fill (%i,%i) %ix%i with 0x%x", X, Y, W, H, word);
258
259         if( X > VGA_WIDTH || Y > VGA_HEIGHT )   return ;
260         if( X + W > VGA_WIDTH ) W = VGA_WIDTH - X;
261         if( Y + H > VGA_HEIGHT )        H = VGA_HEIGHT - Y;
262
263         buf = gVGA_Framebuffer + Y*VGA_WIDTH + X;
264
265         
266         while( H -- ) {
267                  int    i;
268                 for( i = 0; i < W; i ++ )
269                         *buf++ = word;
270                 buf += VGA_WIDTH - W;
271         }
272 }
273
274 void VGA_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H)
275 {
276         Uint16  *src, *dst;
277
278         DstX /= giVT_CharWidth;
279         SrcX /= giVT_CharWidth;
280         W /= giVT_CharWidth;
281
282         DstY /= giVT_CharHeight;
283         SrcY /= giVT_CharHeight;
284         H /= giVT_CharHeight;
285
286 //      Log("(%i,%i) from (%i,%i) %ix%i", DstX, DstY, SrcX, SrcY, W, H);
287
288         if( SrcX > VGA_WIDTH || SrcY > VGA_HEIGHT )     return ;
289         if( SrcX + W > VGA_WIDTH )      W = VGA_WIDTH - SrcX;
290         if( SrcY + H > VGA_HEIGHT )     H = VGA_HEIGHT - SrcY;
291         if( DstX > VGA_WIDTH || DstY > VGA_HEIGHT )     return ;
292         if( DstX + W > VGA_WIDTH )      W = VGA_WIDTH - DstX;
293         if( DstY + H > VGA_HEIGHT )     H = VGA_HEIGHT - DstY;
294
295
296         src = gVGA_Framebuffer + SrcY*VGA_WIDTH + SrcX;
297         dst = gVGA_Framebuffer + DstY*VGA_WIDTH + DstX;
298
299         if( src > dst )
300         {
301                 // Simple copy
302                 while( H-- ) {
303                         memcpy(dst, src, W*2);
304                         dst += VGA_WIDTH;
305                         src += VGA_WIDTH;
306                 }
307         }
308         else
309         {
310                 dst += H*VGA_WIDTH;
311                 src += H*VGA_WIDTH;
312                 while( H -- ) {
313                          int    i;
314                         dst -= VGA_WIDTH-W;
315                         src -= VGA_WIDTH-W;
316                         for( i = W; i --; )     *--dst = *--src;
317                 }
318         }
319 }

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