Coverage Report

Created: 2017-10-25 09:10

/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
}