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

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