/root/src/xen/xen/drivers/video/lfb.c
Line | Count | Source (jump to first uncovered line) |
1 | | /****************************************************************************** |
2 | | * lfb.c |
3 | | * |
4 | | * linear frame buffer handling. |
5 | | */ |
6 | | |
7 | | #include <xen/kernel.h> |
8 | | #include <xen/lib.h> |
9 | | #include <xen/errno.h> |
10 | | #include "lfb.h" |
11 | | #include "font.h" |
12 | | |
13 | 0 | #define MAX_XRES 1900 |
14 | 0 | #define MAX_YRES 1200 |
15 | | #define MAX_BPP 4 |
16 | | #define MAX_FONT_W 8 |
17 | | #define MAX_FONT_H 16 |
18 | | |
19 | | struct lfb_status { |
20 | | struct lfb_prop lfbp; |
21 | | |
22 | | unsigned char *lbuf, *text_buf; |
23 | | unsigned int *line_len; |
24 | | unsigned int xpos, ypos; |
25 | | }; |
26 | | static struct lfb_status lfb; |
27 | | |
28 | | static void lfb_show_line( |
29 | | const unsigned char *text_line, |
30 | | unsigned char *video_line, |
31 | | unsigned int nr_chars, |
32 | | unsigned int nr_cells) |
33 | 0 | { |
34 | 0 | unsigned int i, j, b, bpp, pixel; |
35 | 0 |
|
36 | 0 | bpp = (lfb.lfbp.bits_per_pixel + 7) >> 3; |
37 | 0 |
|
38 | 0 | for ( i = 0; i < lfb.lfbp.font->height; i++ ) |
39 | 0 | { |
40 | 0 | unsigned char *ptr = lfb.lbuf; |
41 | 0 |
|
42 | 0 | for ( j = 0; j < nr_chars; j++ ) |
43 | 0 | { |
44 | 0 | const unsigned char *bits = lfb.lfbp.font->data; |
45 | 0 | bits += ((text_line[j] * lfb.lfbp.font->height + i) * |
46 | 0 | ((lfb.lfbp.font->width + 7) >> 3)); |
47 | 0 | for ( b = lfb.lfbp.font->width; b--; ) |
48 | 0 | { |
49 | 0 | pixel = (*bits & (1u<<b)) ? lfb.lfbp.pixel_on : 0; |
50 | 0 | memcpy(ptr, &pixel, bpp); |
51 | 0 | ptr += bpp; |
52 | 0 | } |
53 | 0 | } |
54 | 0 |
|
55 | 0 | memset(ptr, 0, (lfb.lfbp.width - nr_chars * lfb.lfbp.font->width) * bpp); |
56 | 0 | memcpy(video_line, lfb.lbuf, nr_cells * lfb.lfbp.font->width * bpp); |
57 | 0 | video_line += lfb.lfbp.bytes_per_line; |
58 | 0 | } |
59 | 0 | } |
60 | | |
61 | | /* Fast mode which redraws all modified parts of a 2D text buffer. */ |
62 | | void lfb_redraw_puts(const char *s) |
63 | 0 | { |
64 | 0 | unsigned int i, min_redraw_y = lfb.ypos; |
65 | 0 | char c; |
66 | 0 |
|
67 | 0 | /* Paste characters into text buffer. */ |
68 | 0 | while ( (c = *s++) != '\0' ) |
69 | 0 | { |
70 | 0 | if ( (c == '\n') || (lfb.xpos >= lfb.lfbp.text_columns) ) |
71 | 0 | { |
72 | 0 | if ( ++lfb.ypos >= lfb.lfbp.text_rows ) |
73 | 0 | { |
74 | 0 | min_redraw_y = 0; |
75 | 0 | lfb.ypos = lfb.lfbp.text_rows - 1; |
76 | 0 | memmove(lfb.text_buf, lfb.text_buf + lfb.lfbp.text_columns, |
77 | 0 | lfb.ypos * lfb.lfbp.text_columns); |
78 | 0 | memset(lfb.text_buf + lfb.ypos * lfb.lfbp.text_columns, 0, lfb.xpos); |
79 | 0 | } |
80 | 0 | lfb.xpos = 0; |
81 | 0 | } |
82 | 0 |
|
83 | 0 | if ( c != '\n' ) |
84 | 0 | lfb.text_buf[lfb.xpos++ + lfb.ypos * lfb.lfbp.text_columns] = c; |
85 | 0 | } |
86 | 0 |
|
87 | 0 | /* Render modified section of text buffer to VESA linear framebuffer. */ |
88 | 0 | for ( i = min_redraw_y; i <= lfb.ypos; i++ ) |
89 | 0 | { |
90 | 0 | const unsigned char *line = lfb.text_buf + i * lfb.lfbp.text_columns; |
91 | 0 | unsigned int width; |
92 | 0 |
|
93 | 0 | for ( width = lfb.lfbp.text_columns; width; --width ) |
94 | 0 | if ( line[width - 1] ) |
95 | 0 | break; |
96 | 0 | lfb_show_line(line, |
97 | 0 | lfb.lfbp.lfb + i * lfb.lfbp.font->height * lfb.lfbp.bytes_per_line, |
98 | 0 | width, max(lfb.line_len[i], width)); |
99 | 0 | lfb.line_len[i] = width; |
100 | 0 | } |
101 | 0 |
|
102 | 0 | lfb.lfbp.flush(); |
103 | 0 | } |
104 | | |
105 | | /* Slower line-based scroll mode which interacts better with dom0. */ |
106 | | void lfb_scroll_puts(const char *s) |
107 | 0 | { |
108 | 0 | unsigned int i; |
109 | 0 | char c; |
110 | 0 |
|
111 | 0 | while ( (c = *s++) != '\0' ) |
112 | 0 | { |
113 | 0 | if ( (c == '\n') || (lfb.xpos >= lfb.lfbp.text_columns) ) |
114 | 0 | { |
115 | 0 | unsigned int bytes = (lfb.lfbp.width * |
116 | 0 | ((lfb.lfbp.bits_per_pixel + 7) >> 3)); |
117 | 0 | unsigned char *src = lfb.lfbp.lfb + lfb.lfbp.font->height * lfb.lfbp.bytes_per_line; |
118 | 0 | unsigned char *dst = lfb.lfbp.lfb; |
119 | 0 |
|
120 | 0 | /* New line: scroll all previous rows up one line. */ |
121 | 0 | for ( i = lfb.lfbp.font->height; i < lfb.lfbp.height; i++ ) |
122 | 0 | { |
123 | 0 | memcpy(dst, src, bytes); |
124 | 0 | src += lfb.lfbp.bytes_per_line; |
125 | 0 | dst += lfb.lfbp.bytes_per_line; |
126 | 0 | } |
127 | 0 |
|
128 | 0 | /* Render new line. */ |
129 | 0 | lfb_show_line( |
130 | 0 | lfb.text_buf, |
131 | 0 | lfb.lfbp.lfb + (lfb.lfbp.text_rows-1) * lfb.lfbp.font->height * |
132 | 0 | lfb.lfbp.bytes_per_line, |
133 | 0 | lfb.xpos, lfb.lfbp.text_columns); |
134 | 0 |
|
135 | 0 | lfb.xpos = 0; |
136 | 0 | } |
137 | 0 |
|
138 | 0 | if ( c != '\n' ) |
139 | 0 | lfb.text_buf[lfb.xpos++] = c; |
140 | 0 | } |
141 | 0 |
|
142 | 0 | lfb.lfbp.flush(); |
143 | 0 | } |
144 | | |
145 | | void lfb_carriage_return(void) |
146 | 0 | { |
147 | 0 | lfb.xpos = 0; |
148 | 0 | } |
149 | | |
150 | | int __init lfb_init(struct lfb_prop *lfbp) |
151 | 0 | { |
152 | 0 | if ( lfbp->width > MAX_XRES || lfbp->height > MAX_YRES ) |
153 | 0 | { |
154 | 0 | printk(XENLOG_WARNING "Couldn't initialize a %ux%u framebuffer early.\n", |
155 | 0 | lfbp->width, lfbp->height); |
156 | 0 | return -EINVAL; |
157 | 0 | } |
158 | 0 |
|
159 | 0 | lfb.lfbp = *lfbp; |
160 | 0 |
|
161 | 0 | lfb.lbuf = xmalloc_bytes(lfb.lfbp.bytes_per_line); |
162 | 0 | lfb.text_buf = xzalloc_bytes(lfb.lfbp.text_columns * lfb.lfbp.text_rows); |
163 | 0 | lfb.line_len = xzalloc_array(unsigned int, lfb.lfbp.text_columns); |
164 | 0 |
|
165 | 0 | if ( !lfb.lbuf || !lfb.text_buf || !lfb.line_len ) |
166 | 0 | goto fail; |
167 | 0 |
|
168 | 0 | return 0; |
169 | 0 |
|
170 | 0 | fail: |
171 | 0 | printk(XENLOG_ERR "Couldn't allocate enough memory to drive the framebuffer\n"); |
172 | 0 | lfb_free(); |
173 | 0 |
|
174 | 0 | return -ENOMEM; |
175 | 0 | } |
176 | | |
177 | | void lfb_free(void) |
178 | 0 | { |
179 | 0 | xfree(lfb.lbuf); |
180 | 0 | xfree(lfb.text_buf); |
181 | 0 | xfree(lfb.line_len); |
182 | 0 | } |