~darkmuggle-deactivatedaccount/ubuntu/quantal/grub2/fix-872244

« back to all changes in this revision

Viewing changes to term/i386/pc/vesafb.c

  • Committer: Bazaar Package Importer
  • Author(s): Otavio Salvador
  • Date: 2006-01-05 15:20:40 UTC
  • mto: (17.3.1 squeeze) (1.9.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20060105152040-b72i5pq1a82z22yi
Tags: upstream-1.92
ImportĀ upstreamĀ versionĀ 1.92

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  GRUB  --  GRand Unified Bootloader
 
3
 *  Copyright (C) 2005  Free Software Foundation, Inc.
 
4
 *
 
5
 *  This program is free software; you can redistribute it and/or modify
 
6
 *  it under the terms of the GNU General Public License as published by
 
7
 *  the Free Software Foundation; either version 2 of the License, or
 
8
 *  (at your option) any later version.
 
9
 *
 
10
 *  This program is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with this program; if not, write to the Free Software
 
17
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
18
 */
 
19
 
 
20
#include <grub/machine/memory.h>
 
21
#include <grub/machine/vga.h>
 
22
#include <grub/machine/vbe.h>
 
23
#include <grub/machine/console.h>
 
24
#include <grub/term.h>
 
25
#include <grub/types.h>
 
26
#include <grub/dl.h>
 
27
#include <grub/misc.h>
 
28
#include <grub/normal.h>
 
29
#include <grub/font.h>
 
30
#include <grub/arg.h>
 
31
#include <grub/mm.h>
 
32
#include <grub/env.h>
 
33
 
 
34
#define DEFAULT_CHAR_WIDTH  8
 
35
#define DEFAULT_CHAR_HEIGHT 16
 
36
 
 
37
#define DEFAULT_FG_COLOR    0xa
 
38
#define DEFAULT_BG_COLOR    0x0
 
39
 
 
40
struct grub_colored_char
 
41
{
 
42
  /* An Unicode codepoint.  */
 
43
  grub_uint32_t code;
 
44
 
 
45
  /* Color indexes.  */
 
46
  unsigned char fg_color;
 
47
  unsigned char bg_color;
 
48
 
 
49
  /* The width of this character minus one.  */
 
50
  unsigned char width;
 
51
 
 
52
  /* The column index of this character.  */
 
53
  unsigned char index;
 
54
};
 
55
 
 
56
struct grub_virtual_screen
 
57
{
 
58
  /* Dimensions of the virual screen.  */
 
59
  grub_uint32_t width;
 
60
  grub_uint32_t height;
 
61
 
 
62
  /* Offset in the display.  */
 
63
  grub_uint32_t offset_x;
 
64
  grub_uint32_t offset_y;
 
65
 
 
66
  /* TTY Character sizes.  */
 
67
  grub_uint32_t char_width;
 
68
  grub_uint32_t char_height;
 
69
 
 
70
  /* Virtual screen TTY size.  */
 
71
  grub_uint32_t columns;
 
72
  grub_uint32_t rows;
 
73
 
 
74
  /* Current cursor details.  */
 
75
  grub_uint32_t cursor_x;
 
76
  grub_uint32_t cursor_y;
 
77
  grub_uint8_t cursor_state;
 
78
  grub_uint8_t fg_color;
 
79
  grub_uint8_t bg_color;
 
80
 
 
81
  /* Text buffer for virual screen. Contains (columns * rows) number
 
82
     of entries.  */
 
83
  struct grub_colored_char *text_buffer;
 
84
};
 
85
 
 
86
/* Make seure text buffer is not marked as allocated.  */
 
87
static struct grub_virtual_screen virtual_screen =
 
88
  {
 
89
    .text_buffer = 0
 
90
  };
 
91
 
 
92
static grub_dl_t my_mod;
 
93
static unsigned char *vga_font = 0;
 
94
static grub_uint32_t old_mode = 0;
 
95
 
 
96
static struct grub_vbe_mode_info_block mode_info;
 
97
static grub_uint8_t *framebuffer = 0;
 
98
static grub_uint32_t bytes_per_scan_line = 0;
 
99
 
 
100
static void
 
101
grub_virtual_screen_free (void)
 
102
{
 
103
  /* If virtual screen has been allocated, free it.  */
 
104
  if (virtual_screen.text_buffer != 0)
 
105
    grub_free (virtual_screen.text_buffer);
 
106
 
 
107
  /* Reset virtual screen data.  */
 
108
  grub_memset (&virtual_screen, 0, sizeof (virtual_screen));
 
109
}
 
110
 
 
111
static grub_err_t
 
112
grub_virtual_screen_setup (grub_uint32_t width,
 
113
                           grub_uint32_t height)
 
114
{
 
115
  /* Free old virtual screen.  */
 
116
  grub_virtual_screen_free ();
 
117
 
 
118
  /* Initialize with default data.  */
 
119
  virtual_screen.width = width;
 
120
  virtual_screen.height = height;
 
121
  virtual_screen.offset_x = 0;
 
122
  virtual_screen.offset_y = 0;
 
123
  virtual_screen.char_width = DEFAULT_CHAR_WIDTH;
 
124
  virtual_screen.char_height = DEFAULT_CHAR_HEIGHT;
 
125
  virtual_screen.cursor_x = 0;
 
126
  virtual_screen.cursor_y = 0;
 
127
  virtual_screen.cursor_state = 1;
 
128
  virtual_screen.fg_color = DEFAULT_FG_COLOR;
 
129
  virtual_screen.bg_color = DEFAULT_BG_COLOR;
 
130
 
 
131
  /* Calculate size of text buffer.  */
 
132
  virtual_screen.columns = virtual_screen.width / virtual_screen.char_width;
 
133
  virtual_screen.rows = virtual_screen.height / virtual_screen.char_height;
 
134
 
 
135
  /* Allocate memory for text buffer.  */
 
136
  virtual_screen.text_buffer =
 
137
    (struct grub_colored_char *) grub_malloc (virtual_screen.columns
 
138
                                              * virtual_screen.rows
 
139
                                              * sizeof (*virtual_screen.text_buffer));
 
140
 
 
141
  return grub_errno;
 
142
}
 
143
 
 
144
static grub_err_t
 
145
grub_vesafb_mod_init (void)
 
146
{
 
147
  grub_uint32_t use_mode = GRUB_VBE_DEFAULT_VIDEO_MODE;
 
148
  struct grub_vbe_info_block controller_info;
 
149
  char *modevar;
 
150
 
 
151
  /* Use fonts from VGA bios.  */
 
152
  vga_font = grub_vga_get_font ();
 
153
 
 
154
  /* Check if we have VESA BIOS installed.  */
 
155
  if (grub_vbe_probe (&controller_info) != GRUB_ERR_NONE)
 
156
    return grub_errno;
 
157
 
 
158
  /* Check existence of vbe_mode environment variable.  */
 
159
  modevar = grub_env_get ("vbe_mode");
 
160
 
 
161
  if (modevar != 0)
 
162
    {
 
163
      unsigned long value;
 
164
 
 
165
      value = grub_strtoul (modevar, 0, 0);
 
166
      if (grub_errno == GRUB_ERR_NONE)
 
167
        use_mode = value;
 
168
    }
 
169
 
 
170
  /* Store initial video mode.  */
 
171
  if (grub_vbe_get_video_mode (&old_mode) != GRUB_ERR_NONE)
 
172
    return grub_errno;
 
173
 
 
174
  /* Setup desired graphics mode.  */
 
175
  if (grub_vbe_set_video_mode (use_mode, &mode_info) != GRUB_ERR_NONE)
 
176
    return grub_errno;
 
177
 
 
178
  /* Determine framebuffer and bytes per scan line.  */
 
179
  framebuffer = (grub_uint8_t *) mode_info.phys_base_addr;
 
180
 
 
181
  if (controller_info.version >= 0x300)
 
182
    bytes_per_scan_line = mode_info.lin_bytes_per_scan_line;
 
183
  else
 
184
    bytes_per_scan_line = mode_info.bytes_per_scan_line;
 
185
 
 
186
  /* Create virtual screen.  */
 
187
  if (grub_virtual_screen_setup (mode_info.x_resolution,
 
188
                                 mode_info.y_resolution) != GRUB_ERR_NONE)
 
189
    {
 
190
      grub_vbe_set_video_mode (old_mode, 0);
 
191
      return grub_errno;
 
192
    }
 
193
 
 
194
  /* Make sure frame buffer is black.  */
 
195
  grub_memset (framebuffer,
 
196
               0,
 
197
               bytes_per_scan_line * mode_info.y_resolution);
 
198
 
 
199
  return GRUB_ERR_NONE;
 
200
}
 
201
 
 
202
static grub_err_t
 
203
grub_vesafb_mod_fini (void)
 
204
{
 
205
  grub_virtual_screen_free ();
 
206
 
 
207
  grub_vbe_set_video_mode (old_mode, 0);
 
208
 
 
209
  return GRUB_ERR_NONE;
 
210
}
 
211
 
 
212
static int
 
213
grub_virtual_screen_get_glyph (grub_uint32_t code,
 
214
                               unsigned char bitmap[32],
 
215
                               unsigned *width)
 
216
{
 
217
  if (code > 0x7f)
 
218
    {
 
219
      /* Map some unicode characters to the VGA font, if possible.  */
 
220
      switch (code)
 
221
        {
 
222
        case 0x2190:    /* left arrow */
 
223
          code = 0x1b;
 
224
          break;
 
225
        case 0x2191:    /* up arrow */
 
226
          code = 0x18;
 
227
          break;
 
228
        case 0x2192:    /* right arrow */
 
229
          code = 0x1a;
 
230
          break;
 
231
        case 0x2193:    /* down arrow */
 
232
          code = 0x19;
 
233
          break;
 
234
        case 0x2501:    /* horizontal line */
 
235
          code = 0xc4;
 
236
          break;
 
237
        case 0x2503:    /* vertical line */
 
238
          code = 0xb3;
 
239
          break;
 
240
        case 0x250F:    /* upper-left corner */
 
241
          code = 0xda;
 
242
          break;
 
243
        case 0x2513:    /* upper-right corner */
 
244
          code = 0xbf;
 
245
          break;
 
246
        case 0x2517:    /* lower-left corner */
 
247
          code = 0xc0;
 
248
          break;
 
249
        case 0x251B:    /* lower-right corner */
 
250
          code = 0xd9;
 
251
          break;
 
252
 
 
253
        default:
 
254
          return grub_font_get_glyph (code, bitmap, width);
 
255
        }
 
256
    }
 
257
 
 
258
  if (bitmap)
 
259
    grub_memcpy (bitmap,
 
260
                 vga_font + code * virtual_screen.char_height,
 
261
                 virtual_screen.char_height);
 
262
  *width = 1;
 
263
  return 1;
 
264
}
 
265
 
 
266
static void
 
267
grub_virtual_screen_invalidate_char (struct grub_colored_char *p)
 
268
{
 
269
  p->code = 0xFFFF;
 
270
  
 
271
  if (p->width)
 
272
    {
 
273
      struct grub_colored_char *q;
 
274
 
 
275
      for (q = p + 1; q <= p + p->width; q++)
 
276
        {
 
277
          q->code = 0xFFFF;
 
278
          q->width = 0;
 
279
          q->index = 0;
 
280
        }
 
281
    }
 
282
 
 
283
  p->width = 0;
 
284
}
 
285
 
 
286
static void
 
287
write_char (void)
 
288
{
 
289
  struct grub_colored_char *p;
 
290
  unsigned char bitmap[32];
 
291
  unsigned width;
 
292
  unsigned y;
 
293
  unsigned offset;
 
294
 
 
295
  p = (virtual_screen.text_buffer
 
296
       + virtual_screen.cursor_x
 
297
       + (virtual_screen.cursor_y * virtual_screen.columns));
 
298
 
 
299
  p -= p->index;
 
300
 
 
301
  if (! grub_virtual_screen_get_glyph (p->code, bitmap, &width))
 
302
    {
 
303
      grub_virtual_screen_invalidate_char (p);
 
304
      width = 0;
 
305
    }
 
306
 
 
307
  for (y = 0, offset = 0;
 
308
       y < virtual_screen.char_height;
 
309
       y++, offset++)
 
310
    {
 
311
      unsigned i;
 
312
 
 
313
      for (i = 0;
 
314
           (i < width * virtual_screen.char_width) && (offset < 32);
 
315
           i++)
 
316
        {
 
317
          unsigned char color;
 
318
 
 
319
          if (bitmap[offset] & (1 << (8-i)))
 
320
            {
 
321
              color = p->fg_color;
 
322
            }
 
323
          else
 
324
            {
 
325
              color = p->bg_color;
 
326
            }
 
327
 
 
328
          grub_vbe_set_pixel_index(i + (virtual_screen.cursor_x
 
329
                                        * virtual_screen.char_width),
 
330
                                   y + (virtual_screen.cursor_y
 
331
                                        * virtual_screen.char_height),
 
332
                                   color);
 
333
        }
 
334
    }
 
335
}
 
336
 
 
337
static void
 
338
write_cursor (void)
 
339
{
 
340
  grub_uint32_t x;
 
341
  grub_uint32_t y;
 
342
 
 
343
  for (y = ((virtual_screen.cursor_y + 1) * virtual_screen.char_height) - 3;
 
344
       y < ((virtual_screen.cursor_y + 1) * virtual_screen.char_height) - 1;
 
345
       y++)
 
346
    {
 
347
      for (x = virtual_screen.cursor_x * virtual_screen.char_width;
 
348
           x < (virtual_screen.cursor_x + 1) * virtual_screen.char_width;
 
349
           x++)
 
350
        {
 
351
          grub_vbe_set_pixel_index(x, y, 10);
 
352
        }
 
353
    }
 
354
}
 
355
 
 
356
static void
 
357
scroll_up (void)
 
358
{
 
359
  grub_uint32_t i;
 
360
 
 
361
  /* Scroll text buffer with one line to up.  */
 
362
  grub_memmove (virtual_screen.text_buffer,
 
363
                virtual_screen.text_buffer + virtual_screen.columns,
 
364
                sizeof (*virtual_screen.text_buffer)
 
365
                * virtual_screen.columns
 
366
                * (virtual_screen.rows - 1));
 
367
 
 
368
  /* Clear last line in text buffer.  */
 
369
  for (i = virtual_screen.columns * (virtual_screen.rows - 1);
 
370
       i < virtual_screen.columns * virtual_screen.rows;
 
371
       i++)
 
372
    {
 
373
      virtual_screen.text_buffer[i].code = ' ';
 
374
      virtual_screen.text_buffer[i].fg_color = 0;
 
375
      virtual_screen.text_buffer[i].bg_color = 0;
 
376
      virtual_screen.text_buffer[i].width = 0;
 
377
      virtual_screen.text_buffer[i].index = 0;
 
378
    }
 
379
 
 
380
  /* Scroll frambuffer with one line to up.  */
 
381
  grub_memmove (framebuffer,
 
382
                framebuffer
 
383
                + bytes_per_scan_line * virtual_screen.char_height,
 
384
                bytes_per_scan_line
 
385
                * (mode_info.y_resolution - virtual_screen.char_height));
 
386
 
 
387
  /* Clear last line in framebuffer.  */
 
388
  grub_memset (framebuffer
 
389
               + (bytes_per_scan_line
 
390
                  * (mode_info.y_resolution - virtual_screen.char_height)),
 
391
               0,
 
392
               bytes_per_scan_line * virtual_screen.char_height);
 
393
}
 
394
 
 
395
static void
 
396
grub_vesafb_putchar (grub_uint32_t c)
 
397
{
 
398
  if (c == '\a')
 
399
    /* FIXME */
 
400
    return;
 
401
 
 
402
  if (c == '\b' || c == '\n' || c == '\r')
 
403
    {
 
404
      /* Erase current cursor, if any.  */
 
405
      if (virtual_screen.cursor_state)
 
406
        write_char ();
 
407
 
 
408
      switch (c)
 
409
        {
 
410
        case '\b':
 
411
          if (virtual_screen.cursor_x > 0)
 
412
            virtual_screen.cursor_x--;
 
413
          break;
 
414
          
 
415
        case '\n':
 
416
          if (virtual_screen.cursor_y >= virtual_screen.rows - 1)
 
417
            scroll_up ();
 
418
          else
 
419
            virtual_screen.cursor_y++;
 
420
          break;
 
421
          
 
422
        case '\r':
 
423
          virtual_screen.cursor_x = 0;
 
424
          break;
 
425
        }
 
426
 
 
427
      if (virtual_screen.cursor_state)
 
428
        write_cursor ();
 
429
    }
 
430
  else
 
431
    {
 
432
      unsigned width;
 
433
      struct grub_colored_char *p;
 
434
      
 
435
      grub_virtual_screen_get_glyph (c, 0, &width);
 
436
 
 
437
      if (virtual_screen.cursor_x + width > virtual_screen.columns)
 
438
        grub_putchar ('\n');
 
439
 
 
440
      p = (virtual_screen.text_buffer +
 
441
           virtual_screen.cursor_x +
 
442
           virtual_screen.cursor_y * virtual_screen.columns);
 
443
      p->code = c;
 
444
      p->fg_color = virtual_screen.fg_color;
 
445
      p->bg_color = virtual_screen.bg_color;
 
446
      p->width = width - 1;
 
447
      p->index = 0;
 
448
 
 
449
      if (width > 1)
 
450
        {
 
451
          unsigned i;
 
452
 
 
453
          for (i = 1; i < width; i++)
 
454
            {
 
455
              p[i].code = ' ';
 
456
              p[i].width = width - 1;
 
457
              p[i].index = i;
 
458
            }
 
459
        }
 
460
          
 
461
      write_char ();
 
462
  
 
463
      virtual_screen.cursor_x += width;
 
464
      if (virtual_screen.cursor_x >= virtual_screen.columns)
 
465
        {
 
466
          virtual_screen.cursor_x = 0;
 
467
          
 
468
          if (virtual_screen.cursor_y >= virtual_screen.rows - 1)
 
469
            scroll_up ();
 
470
          else
 
471
            virtual_screen.cursor_y++;
 
472
        }
 
473
 
 
474
      if (virtual_screen.cursor_state)
 
475
        write_cursor ();
 
476
    }
 
477
}
 
478
 
 
479
static grub_ssize_t
 
480
grub_vesafb_getcharwidth (grub_uint32_t c)
 
481
{
 
482
  unsigned width;
 
483
  
 
484
  if (! grub_virtual_screen_get_glyph (c, 0, &width))
 
485
    return 0;
 
486
 
 
487
  return width;
 
488
}
 
489
 
 
490
static grub_uint16_t
 
491
grub_virtual_screen_getwh (void)
 
492
{
 
493
  return (virtual_screen.columns << 8) | virtual_screen.rows;
 
494
}
 
495
 
 
496
static grub_uint16_t
 
497
grub_virtual_screen_getxy (void)
 
498
{
 
499
  return ((virtual_screen.cursor_x << 8) | virtual_screen.cursor_y);
 
500
}
 
501
 
 
502
static void
 
503
grub_vesafb_gotoxy (grub_uint8_t x, grub_uint8_t y)
 
504
{
 
505
  if (x >= virtual_screen.columns || y >= virtual_screen.rows)
 
506
    {
 
507
      grub_error (GRUB_ERR_OUT_OF_RANGE, "invalid point (%u,%u)",
 
508
                  (unsigned) x, (unsigned) y);
 
509
      return;
 
510
    }
 
511
 
 
512
  if (virtual_screen.cursor_state)
 
513
    write_char ();
 
514
 
 
515
  virtual_screen.cursor_x = x;
 
516
  virtual_screen.cursor_y = y;
 
517
 
 
518
  if (virtual_screen.cursor_state)
 
519
    write_cursor ();
 
520
}
 
521
 
 
522
static void
 
523
grub_virtual_screen_cls (void)
 
524
{
 
525
  grub_uint32_t i;
 
526
 
 
527
  for (i = 0; i < virtual_screen.columns * virtual_screen.rows; i++)
 
528
    {
 
529
      virtual_screen.text_buffer[i].code = ' ';
 
530
      virtual_screen.text_buffer[i].fg_color = 0;
 
531
      virtual_screen.text_buffer[i].bg_color = 0;
 
532
      virtual_screen.text_buffer[i].width = 0;
 
533
      virtual_screen.text_buffer[i].index = 0;
 
534
    }
 
535
 
 
536
  virtual_screen.cursor_x = virtual_screen.cursor_y = 0;
 
537
}
 
538
 
 
539
static void
 
540
grub_vesafb_cls (void)
 
541
{
 
542
  grub_virtual_screen_cls ();
 
543
 
 
544
  grub_memset (framebuffer,
 
545
               0, 
 
546
               mode_info.y_resolution * bytes_per_scan_line);
 
547
}
 
548
 
 
549
static void
 
550
grub_virtual_screen_setcolorstate (grub_term_color_state state)
 
551
{
 
552
  switch (state)
 
553
    {
 
554
    case GRUB_TERM_COLOR_STANDARD:
 
555
    case GRUB_TERM_COLOR_NORMAL:
 
556
      virtual_screen.fg_color = DEFAULT_FG_COLOR;
 
557
      virtual_screen.bg_color = DEFAULT_BG_COLOR;
 
558
      break;
 
559
    case GRUB_TERM_COLOR_HIGHLIGHT:
 
560
      virtual_screen.fg_color = DEFAULT_BG_COLOR;
 
561
      virtual_screen.bg_color = DEFAULT_FG_COLOR;
 
562
      break;
 
563
    default:
 
564
      break;
 
565
    }
 
566
}
 
567
 
 
568
static void
 
569
grub_virtual_screen_setcolor (grub_uint8_t normal_color __attribute__ ((unused)),
 
570
                              grub_uint8_t highlight_color __attribute__ ((unused)))
 
571
{
 
572
  /* FIXME */
 
573
}
 
574
 
 
575
static void
 
576
grub_vesafb_setcursor (int on)
 
577
{
 
578
  if (virtual_screen.cursor_state != on)
 
579
    {
 
580
      if (virtual_screen.cursor_state)
 
581
        write_char ();
 
582
      else
 
583
        write_cursor ();
 
584
 
 
585
      virtual_screen.cursor_state = on;
 
586
    }
 
587
}
 
588
 
 
589
static struct grub_term grub_vesafb_term =
 
590
  {
 
591
    .name = "vesafb",
 
592
    .init = grub_vesafb_mod_init,
 
593
    .fini = grub_vesafb_mod_fini,
 
594
    .putchar = grub_vesafb_putchar,
 
595
    .getcharwidth = grub_vesafb_getcharwidth,
 
596
    .checkkey = grub_console_checkkey,
 
597
    .getkey = grub_console_getkey,
 
598
    .getwh = grub_virtual_screen_getwh,
 
599
    .getxy = grub_virtual_screen_getxy,
 
600
    .gotoxy = grub_vesafb_gotoxy,
 
601
    .cls = grub_vesafb_cls,
 
602
    .setcolorstate = grub_virtual_screen_setcolorstate,
 
603
    .setcolor = grub_virtual_screen_setcolor,
 
604
    .setcursor = grub_vesafb_setcursor,
 
605
    .flags = 0,
 
606
    .next = 0
 
607
  };
 
608
 
 
609
GRUB_MOD_INIT(vesafb)
 
610
{
 
611
  my_mod = mod;
 
612
  grub_term_register (&grub_vesafb_term);
 
613
}
 
614
 
 
615
GRUB_MOD_FINI(vesafb)
 
616
{
 
617
  grub_term_unregister (&grub_vesafb_term);
 
618
}