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 <debug.h>
30 #include <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 {
59     unsigned x, y, data;
60     stride -= FONT_WIDTH;
61 
62     data = glyph[0];
63     for (y = 0; y < (FONT_HEIGHT / 2); ++y) {
64         for (x = 0; x < FONT_WIDTH; ++x) {
65             if (data & 1)
66                 *pixels = paint;
67             data >>= 1;
68             pixels++;
69         }
70         pixels += stride;
71     }
72 
73     data = glyph[1];
74     for (y = 0; y < (FONT_HEIGHT / 2); y++) {
75         for (x = 0; x < FONT_WIDTH; x++) {
76             if (data & 1)
77                 *pixels = paint;
78             data >>= 1;
79             pixels++;
80         }
81         pixels += stride;
82     }
83 }
84 
fbcon_flush(void)85 static void fbcon_flush(void)
86 {
87     if (config->update_start)
88         config->update_start();
89     if (config->update_done)
90         while (!config->update_done());
91 }
92 
93 /* TODO: Take stride into account */
fbcon_scroll_up(void)94 static void fbcon_scroll_up(void)
95 {
96     unsigned short *dst = config->base;
97     unsigned short *src = dst + (config->width * FONT_HEIGHT);
98     unsigned count = config->width * (config->height - FONT_HEIGHT);
99 
100     while (count--) {
101         *dst++ = *src++;
102     }
103 
104     count = config->width * FONT_HEIGHT;
105     while (count--) {
106         *dst++ = BGCOLOR;
107     }
108 
109     fbcon_flush();
110 }
111 
112 /* TODO: take stride into account */
fbcon_clear(void)113 static void fbcon_clear(void)
114 {
115     uint16_t *dst = config->base;
116     unsigned count = config->width * config->height;
117 
118     cur_pos.x = 0;
119     cur_pos.y = 0;
120 
121     while (count--)
122         *dst++ = BGCOLOR;
123 }
124 
125 
fbcon_set_colors(unsigned bg,unsigned fg)126 static void fbcon_set_colors(unsigned bg, unsigned fg)
127 {
128     BGCOLOR = bg;
129     FGCOLOR = fg;
130 }
131 
fbcon_putc(char c)132 void fbcon_putc(char c)
133 {
134     uint16_t *pixels;
135 
136     /* ignore anything that happens before fbcon is initialized */
137     if (!config)
138         return;
139 
140     if ((unsigned char)c > 127)
141         return;
142     if ((unsigned char)c < 32) {
143         if (c == '\n')
144             goto newline;
145         else if (c == '\r')
146             cur_pos.x = 0;
147         return;
148     }
149 
150     pixels = config->base;
151     pixels += cur_pos.y * FONT_HEIGHT * config->width;
152     pixels += cur_pos.x * (FONT_WIDTH + 1);
153     fbcon_drawglyph(pixels, FGCOLOR, config->stride,
154                     font5x12 + (c - 32) * 2);
155 
156     cur_pos.x++;
157     if (cur_pos.x < max_pos.x)
158         return;
159 
160 newline:
161     cur_pos.y++;
162     cur_pos.x = 0;
163     if (cur_pos.y >= max_pos.y) {
164         cur_pos.y = max_pos.y - 1;
165         fbcon_scroll_up();
166     } else
167         fbcon_flush();
168 }
169 
fbcon_setup(struct fbcon_config * _config)170 void fbcon_setup(struct fbcon_config *_config)
171 {
172     uint32_t bg;
173     uint32_t fg;
174 
175     ASSERT(_config);
176 
177     config = _config;
178 
179     switch (config->format) {
180         case FB_FORMAT_RGB565:
181             bg = RGB565_BLUE;
182             fg = RGB565_WHITE;
183             break;
184 
185         default:
186             dprintf(CRITICAL, "unknown framebuffer pixel format\n");
187             ASSERT(0);
188             break;
189     }
190 
191     fbcon_set_colors(bg, fg);
192 
193     fbcon_clear();
194     fbcon_flush();
195 
196     cur_pos.x = 0;
197     cur_pos.y = 0;
198     max_pos.x = config->width / (FONT_WIDTH+1);
199     max_pos.y = (config->height - 1) / FONT_HEIGHT;
200 }
201