2 * Copyright 2005-2009, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
7 #include <frame_buffer_console.h>
14 #include <KernelExport.h>
17 #include <boot_item.h>
20 #include <boot/kernel_args.h>
23 #include <vesa_info.h>
31 //#define TRACE_FB_CONSOLE
32 #ifdef TRACE_FB_CONSOLE
33 # define TRACE(x) dprintf x
47 int32 bytes_per_pixel
;
56 // Palette is (white and black are exchanged):
57 // 0 - white, 1 - blue, 2 - green, 3 - cyan, 4 - red, 5 - magenta, 6 - yellow,
59 // 8-15 - same but bright (we're ignoring those)
61 static uint8 sPalette8
[] = {
62 63, 32, 52, 70, 42, 88, 67, 0,
64 static uint16 sPalette15
[] = {
65 // 0bbbbbgggggrrrrr (5-5-5)
66 0x7fff, 0x1993, 0x2660, 0x0273, 0x6400, 0x390f, 0x6ea0, 0x0000,
68 static uint16 sPalette16
[] = {
69 // bbbbbggggggrrrrr (5-6-5)
70 0xffff, 0x3333, 0x4cc0, 0x04d3, 0xc800, 0x722f, 0xdd40, 0x0000,
72 static uint32 sPalette32
[] = {
73 // is also used by 24 bit modes
84 static struct console_info sConsole
;
87 static struct frame_buffer_boot_info sBootInfo
;
88 static struct vesa_mode
* sVesaModes
;
93 foreground_color(uint8 attr
)
100 background_color(uint8 attr
)
102 return (attr
>> 4) & 0x7;
107 get_palette_entry(uint8 index
)
109 switch (sConsole
.depth
) {
111 return &sPalette8
[index
];
113 return (uint8
*)&sPalette15
[index
];
115 return (uint8
*)&sPalette16
[index
];
117 return (uint8
*)&sPalette32
[index
];
123 render_glyph(int32 x
, int32 y
, uint8 glyph
, uint8 attr
)
129 if (sConsole
.depth
>= 8) {
130 uint8
* base
= (uint8
*)(sConsole
.frame_buffer
131 + sConsole
.bytes_per_row
* y
* CHAR_HEIGHT
132 + x
* CHAR_WIDTH
* sConsole
.bytes_per_pixel
);
133 uint8
* color
= get_palette_entry(foreground_color(attr
));
134 uint8
* backgroundColor
= get_palette_entry(background_color(attr
));
136 for (y
= 0; y
< CHAR_HEIGHT
; y
++) {
137 uint8 bits
= FONT
[CHAR_HEIGHT
* glyph
+ y
];
138 for (x
= 0; x
< CHAR_WIDTH
; x
++) {
139 for (int32 i
= 0; i
< sConsole
.bytes_per_pixel
; i
++) {
141 base
[x
* sConsole
.bytes_per_pixel
+ i
] = color
[i
];
143 base
[x
* sConsole
.bytes_per_pixel
+ i
]
144 = backgroundColor
[i
];
150 base
+= sConsole
.bytes_per_row
;
153 // VGA mode will be treated as monochrome
154 // (ie. only the first plane will be used)
156 uint8
* base
= (uint8
*)(sConsole
.frame_buffer
157 + sConsole
.bytes_per_row
* y
* CHAR_HEIGHT
+ x
* CHAR_WIDTH
/ 8);
158 uint8 baseOffset
= (x
* CHAR_WIDTH
) & 0x7;
160 for (y
= 0; y
< CHAR_HEIGHT
; y
++) {
161 uint8 bits
= FONT
[CHAR_HEIGHT
* glyph
+ y
];
162 uint8 offset
= baseOffset
;
163 uint8 mask
= 1 << (7 - baseOffset
);
165 for (x
= 0; x
< CHAR_WIDTH
; x
++) {
171 base
[offset
/ 8] &= ~mask
;
173 base
[offset
/ 8] |= mask
;
180 base
+= sConsole
.bytes_per_row
;
187 draw_cursor(int32 x
, int32 y
)
192 x
*= CHAR_WIDTH
* sConsole
.bytes_per_pixel
;
194 int32 endX
= x
+ CHAR_WIDTH
* sConsole
.bytes_per_pixel
;
195 int32 endY
= y
+ CHAR_HEIGHT
;
196 uint8
* base
= (uint8
*)(sConsole
.frame_buffer
+ y
* sConsole
.bytes_per_row
);
198 if (sConsole
.depth
< 8) {
203 for (; y
< endY
; y
++) {
204 for (int32 x2
= x
; x2
< endX
; x2
++)
205 base
[x2
] = ~base
[x2
];
207 base
+= sConsole
.bytes_per_row
;
213 console_get_size(int32
* _width
, int32
* _height
)
215 *_width
= sConsole
.columns
;
216 *_height
= sConsole
.rows
;
223 console_move_cursor(int32 x
, int32 y
)
225 if (!frame_buffer_console_available())
228 draw_cursor(sConsole
.cursor_x
, sConsole
.cursor_y
);
231 sConsole
.cursor_x
= x
;
232 sConsole
.cursor_y
= y
;
237 console_put_glyph(int32 x
, int32 y
, uint8 glyph
, uint8 attr
)
239 if (x
>= sConsole
.columns
|| y
>= sConsole
.rows
240 || !frame_buffer_console_available())
243 render_glyph(x
, y
, glyph
, attr
);
248 console_fill_glyph(int32 x
, int32 y
, int32 width
, int32 height
, uint8 glyph
,
251 if (x
>= sConsole
.columns
|| y
>= sConsole
.rows
252 || !frame_buffer_console_available())
255 int32 left
= x
+ width
;
256 if (left
> sConsole
.columns
)
257 left
= sConsole
.columns
;
259 int32 bottom
= y
+ height
;
260 if (bottom
> sConsole
.rows
)
261 bottom
= sConsole
.rows
;
263 for (; y
< bottom
; y
++) {
264 for (int32 x2
= x
; x2
< left
; x2
++) {
265 render_glyph(x2
, y
, glyph
, attr
);
272 console_blit(int32 srcx
, int32 srcy
, int32 width
, int32 height
, int32 destx
,
275 if (!frame_buffer_console_available())
278 height
*= CHAR_HEIGHT
;
280 desty
*= CHAR_HEIGHT
;
282 if (sConsole
.depth
>= 8) {
283 width
*= CHAR_WIDTH
* sConsole
.bytes_per_pixel
;
284 srcx
*= CHAR_WIDTH
* sConsole
.bytes_per_pixel
;
285 destx
*= CHAR_WIDTH
* sConsole
.bytes_per_pixel
;
288 width
= width
* CHAR_WIDTH
/ 8;
289 srcx
= srcx
* CHAR_WIDTH
/ 8;
290 destx
= destx
* CHAR_WIDTH
/ 8;
293 for (int32 y
= 0; y
< height
; y
++) {
294 memmove((void*)(sConsole
.frame_buffer
+ (desty
+ y
)
295 * sConsole
.bytes_per_row
+ destx
),
296 (void*)(sConsole
.frame_buffer
+ (srcy
+ y
) * sConsole
.bytes_per_row
303 console_clear(uint8 attr
)
305 if (!frame_buffer_console_available())
308 switch (sConsole
.bytes_per_pixel
) {
310 if (sConsole
.depth
>= 8) {
311 memset((void*)sConsole
.frame_buffer
,
312 sPalette8
[background_color(attr
)],
313 sConsole
.height
* sConsole
.bytes_per_row
);
315 // special case for VGA mode
316 memset((void*)sConsole
.frame_buffer
, 0xff,
317 sConsole
.height
* sConsole
.bytes_per_row
);
322 uint8
* base
= (uint8
*)sConsole
.frame_buffer
;
323 uint8
* color
= get_palette_entry(background_color(attr
));
325 for (int32 y
= 0; y
< sConsole
.height
; y
++) {
326 for (int32 x
= 0; x
< sConsole
.width
; x
++) {
327 for (int32 i
= 0; i
< sConsole
.bytes_per_pixel
; i
++) {
328 base
[x
* sConsole
.bytes_per_pixel
+ i
] = color
[i
];
331 base
+= sConsole
.bytes_per_row
;
337 sConsole
.cursor_x
= -1;
338 sConsole
.cursor_y
= -1;
343 console_std_ops(int32 op
, ...)
347 return frame_buffer_console_available() ? B_OK
: B_ERROR
;
348 case B_MODULE_UNINIT
:
357 console_module_info gFrameBufferConsoleModule
= {
359 FRAME_BUFFER_CONSOLE_MODULE_NAME
,
364 &console_move_cursor
,
376 frame_buffer_console_available(void)
378 return sConsole
.frame_buffer
!= 0;
383 frame_buffer_update(addr_t baseAddress
, int32 width
, int32 height
, int32 depth
,
386 TRACE(("frame_buffer_update(buffer = %p, width = %ld, height = %ld, "
387 "depth = %ld, bytesPerRow = %ld)\n", (void*)baseAddress
, width
, height
,
388 depth
, bytesPerRow
));
390 mutex_lock(&sConsole
.lock
);
392 sConsole
.frame_buffer
= baseAddress
;
393 sConsole
.width
= width
;
394 sConsole
.height
= height
;
395 sConsole
.depth
= depth
;
396 sConsole
.bytes_per_pixel
= (depth
+ 7) / 8;
397 sConsole
.bytes_per_row
= bytesPerRow
;
398 sConsole
.columns
= sConsole
.width
/ CHAR_WIDTH
;
399 sConsole
.rows
= sConsole
.height
/ CHAR_HEIGHT
;
401 // initially, the cursor is hidden
402 sConsole
.cursor_x
= -1;
403 sConsole
.cursor_y
= -1;
405 TRACE(("framebuffer mapped at %p, %ld columns, %ld rows\n",
406 (void*)sConsole
.frame_buffer
, sConsole
.columns
, sConsole
.rows
));
408 mutex_unlock(&sConsole
.lock
);
415 frame_buffer_console_init(kernel_args
* args
)
417 if (!args
->frame_buffer
.enabled
)
420 mutex_init(&sConsole
.lock
, "console_lock");
423 sConsole
.area
= map_physical_memory("vesa frame buffer",
424 args
->frame_buffer
.physical_buffer
.start
,
425 args
->frame_buffer
.physical_buffer
.size
, B_ANY_KERNEL_ADDRESS
,
426 B_READ_AREA
| B_WRITE_AREA
| B_USER_CLONEABLE_AREA
, &frameBuffer
);
427 if (sConsole
.area
< 0)
428 return sConsole
.area
;
430 frame_buffer_update((addr_t
)frameBuffer
, args
->frame_buffer
.width
,
431 args
->frame_buffer
.height
, args
->frame_buffer
.depth
,
432 args
->frame_buffer
.bytes_per_row
);
434 sBootInfo
.area
= sConsole
.area
;
435 sBootInfo
.physical_frame_buffer
= args
->frame_buffer
.physical_buffer
.start
;
436 sBootInfo
.frame_buffer
= (addr_t
)frameBuffer
;
437 sBootInfo
.width
= args
->frame_buffer
.width
;
438 sBootInfo
.height
= args
->frame_buffer
.height
;
439 sBootInfo
.depth
= args
->frame_buffer
.depth
;
440 sBootInfo
.bytes_per_row
= args
->frame_buffer
.bytes_per_row
;
441 sBootInfo
.vesa_capabilities
= args
->vesa_capabilities
;
443 add_boot_item(FRAME_BUFFER_BOOT_INFO
, &sBootInfo
,
444 sizeof(frame_buffer_boot_info
));
446 sVesaModes
= (vesa_mode
*)malloc(args
->vesa_modes_size
);
447 if (sVesaModes
!= NULL
&& args
->vesa_modes_size
> 0) {
448 memcpy(sVesaModes
, args
->vesa_modes
, args
->vesa_modes_size
);
449 add_boot_item(VESA_MODES_BOOT_INFO
, sVesaModes
, args
->vesa_modes_size
);
452 if (args
->edid_info
!= NULL
) {
453 edid1_info
* info
= (edid1_info
*)malloc(sizeof(edid1_info
));
455 memcpy(info
, args
->edid_info
, sizeof(edid1_info
));
456 add_boot_item(VESA_EDID_BOOT_INFO
, info
, sizeof(edid1_info
));
465 frame_buffer_console_init_post_modules(kernel_args
* args
)
467 if (sConsole
.frame_buffer
== 0)
470 // try to set frame buffer memory to write combined
472 return vm_set_area_memory_type(sConsole
.area
,
473 args
->frame_buffer
.physical_buffer
.start
, B_MTR_WC
);
481 _user_frame_buffer_update(addr_t baseAddress
, int32 width
, int32 height
,
482 int32 depth
, int32 bytesPerRow
)
484 debug_stop_screen_debug_output();
487 return B_NOT_ALLOWED
;
488 if (IS_USER_ADDRESS(baseAddress
) && baseAddress
!= 0)
489 return B_BAD_ADDRESS
;
491 return frame_buffer_update(baseAddress
, width
, height
, depth
, bytesPerRow
);