1 /*
2  * Copyright (c) 2008, Google Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *  * Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  *  * Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in
12  *    the documentation and/or other materials provided with the
13  *    distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <lk/debug.h>
30 #include <lk/err.h>
31 #include <stdlib.h>
32 #include <assert.h>
33 #include <dev/fbcon.h>
34 
35 #include "font5x12.h"
36 
37 struct pos {
38     int x;
39     int y;
40 };
41 
42 static struct fbcon_config *config = NULL;
43 
44 #define RGB565_BLUE     0x001f
45 #define RGB565_WHITE        0xffff
46 
47 #define FONT_WIDTH      5
48 #define FONT_HEIGHT     12
49 
50 static uint16_t         BGCOLOR;
51 static uint16_t         FGCOLOR;
52 
53 static struct pos       cur_pos;
54 static struct pos       max_pos;
55 
fbcon_drawglyph(uint16_t * pixels,uint16_t paint,unsigned stride,unsigned * glyph)56 static void fbcon_drawglyph(uint16_t *pixels, uint16_t paint, unsigned stride,
57                             unsigned *glyph) {
58     unsigned x, y, data;
59     stride -= FONT_WIDTH;
60 
61     data = glyph[0];
62     for (y = 0; y < (FONT_HEIGHT / 2); ++y) {
63         for (x = 0; x < FONT_WIDTH; ++x) {
64             if (data & 1)
65                 *pixels = paint;
66             data >>= 1;
67             pixels++;
68         }
69         pixels += stride;
70     }
71 
72     data = glyph[1];
73     for (y = 0; y < (FONT_HEIGHT / 2); y++) {
74         for (x = 0; x < FONT_WIDTH; x++) {
75             if (data & 1)
76                 *pixels = paint;
77             data >>= 1;
78             pixels++;
79         }
80         pixels += stride;
81     }
82 }
83 
fbcon_flush(void)84 static void fbcon_flush(void) {
85     if (config->update_start)
86         config->update_start();
87     if (config->update_done)
88         while (!config->update_done());
89 }
90 
91 /* TODO: Take stride into account */
fbcon_scroll_up(void)92 static void fbcon_scroll_up(void) {
93     unsigned short *dst = config->base;
94     unsigned short *src = dst + (config->width * FONT_HEIGHT);
95     unsigned count = config->width * (config->height - FONT_HEIGHT);
96 
97     while (count--) {
98         *dst++ = *src++;
99     }
100 
101     count = config->width * FONT_HEIGHT;
102     while (count--) {
103         *dst++ = BGCOLOR;
104     }
105 
106     fbcon_flush();
107 }
108 
109 /* TODO: take stride into account */
fbcon_clear(void)110 static void fbcon_clear(void) {
111     uint16_t *dst = config->base;
112     unsigned count = config->width * config->height;
113 
114     cur_pos.x = 0;
115     cur_pos.y = 0;
116 
117     while (count--)
118         *dst++ = BGCOLOR;
119 }
120 
121 
fbcon_set_colors(unsigned bg,unsigned fg)122 static void fbcon_set_colors(unsigned bg, unsigned fg) {
123     BGCOLOR = bg;
124     FGCOLOR = fg;
125 }
126 
fbcon_putc(char c)127 void fbcon_putc(char c) {
128     uint16_t *pixels;
129 
130     /* ignore anything that happens before fbcon is initialized */
131     if (!config)
132         return;
133 
134     if ((unsigned char)c > 127)
135         return;
136     if ((unsigned char)c < 32) {
137         if (c == '\n')
138             goto newline;
139         else if (c == '\r')
140             cur_pos.x = 0;
141         return;
142     }
143 
144     pixels = config->base;
145     pixels += cur_pos.y * FONT_HEIGHT * config->width;
146     pixels += cur_pos.x * (FONT_WIDTH + 1);
147     fbcon_drawglyph(pixels, FGCOLOR, config->stride,
148                     font5x12 + (c - 32) * 2);
149 
150     cur_pos.x++;
151     if (cur_pos.x < max_pos.x)
152         return;
153 
154 newline:
155     cur_pos.y++;
156     cur_pos.x = 0;
157     if (cur_pos.y >= max_pos.y) {
158         cur_pos.y = max_pos.y - 1;
159         fbcon_scroll_up();
160     } else
161         fbcon_flush();
162 }
163 
fbcon_setup(struct fbcon_config * _config)164 void fbcon_setup(struct fbcon_config *_config) {
165     uint32_t bg;
166     uint32_t fg;
167 
168     ASSERT(_config);
169 
170     config = _config;
171 
172     switch (config->format) {
173         case FB_FORMAT_RGB565:
174             bg = RGB565_BLUE;
175             fg = RGB565_WHITE;
176             break;
177 
178         default:
179             dprintf(CRITICAL, "unknown framebuffer pixel format\n");
180             ASSERT(0);
181             break;
182     }
183 
184     fbcon_set_colors(bg, fg);
185 
186     fbcon_clear();
187     fbcon_flush();
188 
189     cur_pos.x = 0;
190     cur_pos.y = 0;
191     max_pos.x = config->width / (FONT_WIDTH+1);
192     max_pos.y = (config->height - 1) / FONT_HEIGHT;
193 }
194