1/*
2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29/*
30 * text_console.c
31 *
32 * VGA text console support.
33 */
34
35#include <architecture/i386/pio.h>
36#include <console/video_console.h>
37#include "text_console.h"
38
39/*
40 * Macros and typedefs.
41 */
42typedef short  csrpos_t;    /* cursor position, ONE_SPACE bytes per char */
43
44#define ONE_SPACE       2                       /* bytes per character */
45#define ONE_LINE        (vga_cols * ONE_SPACE)  /* number of bytes in line */
46#define ONE_PAGE        (vga_rows * ONE_LINE)   /* number of bytes in page */
47#define SPACE_CHAR      0x20
48
49#define VGA_FB_START    0x0b8000
50#define VGA_FB_SIZE     0x8000
51#define VGA_IDX_REG     0x3d4
52#define VGA_IO_REG      0x3d5
53
54/*
55 * Commands sent to graphics adapter.
56 */
57#define VGA_C_START         0x0a    /* cursor start position, on/off bit */
58#define VGA_C_LOW           0x0f    /* return low byte of cursor addr */
59#define VGA_C_HIGH          0x0e    /* high byte */
60
61/*
62 * Attributes for character sent to display.
63 */
64#define VGA_ATTR_NORMAL     0x07
65#define VGA_ATTR_REVERSE    0x70
66
67/*
68 * Cursor Start Register bit fields.
69 */
70#define VGA_CURSOR_CS       0x1F
71#define VGA_CURSOR_ON       0x20
72
73/*
74 * Convert from XY coordinate to a location in display memory.
75 */
76#define XY_TO_CSRPOS(x, y)    (((y) * vga_cols + (x)) * ONE_SPACE)
77
78/*
79 * Globals.
80 */
81static short     vga_idx_reg;		/* location of VGA index register */
82static short     vga_io_reg;		/* location of VGA data register */
83static short     vga_cols = 80;		/* number of columns */
84static short     vga_rows = 25;		/* number of rows */
85static char      vga_attr;		/* current character attribute */
86static char      vga_attr_rev;		/* current reverse attribute */
87static char      vga_cursor_start;	/* cached cursor start scan line */
88static unsigned char *vram_start;	/* VM start of VGA frame buffer */
89
90/*
91 * Functions in kdasm.s.
92 */
93extern void kd_slmwd(unsigned char * pos, int count, unsigned short val);
94extern void kd_slmscu(unsigned char * from, unsigned char * to, int count);
95extern void kd_slmscd(unsigned char * from, unsigned char * to, int count);
96
97/*
98 * move_up
99 *
100 * Block move up for VGA.
101 */
102static void
103move_up( csrpos_t  from,
104         csrpos_t  to,
105         int       count)
106{
107    if (vram_start == 0) return;
108    kd_slmscu( vram_start + from, vram_start + to, count );
109}
110
111/*
112 * move_down
113 *
114 * Block move down for VGA.
115 */
116static void
117move_down( csrpos_t  from,
118           csrpos_t  to,
119           int       count )
120{
121    if (vram_start == 0) return;
122    kd_slmscd( vram_start + from, vram_start + to, count );
123}
124
125/*
126 * clear_block
127 *
128 * Fast clear for VGA.
129 */
130static void
131clear_block( csrpos_t  start,
132             int       size,
133             char      attr)
134{
135    if (vram_start == 0) return;
136    kd_slmwd( vram_start + start, size,
137              ((unsigned short) attr << 8) + SPACE_CHAR);
138}
139
140/*
141 * set_cursor_position
142 *
143 * This function sets the hardware cursor position
144 * on the screen.
145 */
146static void
147set_cursor_position( csrpos_t newpos )
148{
149    short curpos;  /* position, not scaled for attribute byte */
150
151    curpos = newpos / ONE_SPACE;
152
153    outb(vga_idx_reg, VGA_C_HIGH);
154    outb(vga_io_reg, (unsigned char)(curpos >> 8));
155
156    outb(vga_idx_reg, VGA_C_LOW);
157    outb(vga_io_reg, (unsigned char)(curpos & 0xff));
158}
159
160/*
161 * set_cursor_enable
162 *
163 * Allow the cursor to be turned on or off.
164 */
165static void
166set_cursor_enable( boolean_t enable )
167{
168    outb(vga_idx_reg, VGA_C_START);
169    outb(vga_io_reg, vga_cursor_start |
170                     (enable == TRUE ? VGA_CURSOR_ON : 0));
171}
172
173/*
174 * display_char
175 *
176 * Display attributed character for VGA (mode 3).
177 */
178static void
179display_char( csrpos_t    pos,      /* where to put it */
180              char        ch,       /* the character */
181              char        attr )    /* its attribute */
182{
183    if (vram_start == 0) return;
184    *(vram_start + pos)     = ch;
185    *(vram_start + pos + 1) = attr;
186}
187
188/*
189 * vga_init
190 *
191 * Initialize the VGA text console.
192 */
193static void
194vga_init(int cols, int rows, unsigned char * addr)
195{
196    vram_start   = addr;
197    vga_idx_reg  = VGA_IDX_REG;
198    vga_io_reg   = VGA_IO_REG;
199    vga_rows     = rows;
200    vga_cols     = cols;
201    vga_attr     = VGA_ATTR_NORMAL;
202    vga_attr_rev = VGA_ATTR_REVERSE;
203
204    /* cache cursor start position */
205    outb(vga_idx_reg, VGA_C_START);
206    vga_cursor_start = inb(vga_io_reg) & VGA_CURSOR_CS;
207
208    /* defaults to a hidden hw cursor */
209    set_cursor_enable( FALSE );
210}
211
212/*
213 * tc_scroll_up
214 *
215 * Scroll the screen up 'n' character lines.
216 */
217void
218tc_scroll_up(int lines, __unused unsigned int top, __unused unsigned int bottom)
219{
220    csrpos_t  to;
221    csrpos_t  from;
222    int       size;
223
224    /* scroll up */
225    to   = 0;
226    from = ONE_LINE * lines;
227    size = ( ONE_PAGE - ( ONE_LINE * lines ) ) / ONE_SPACE;
228    move_up(from, to, size);
229
230    /* clear bottom line */
231    to   = ( ( vga_rows - lines) * ONE_LINE );
232    size = ( ONE_LINE * lines ) / ONE_SPACE;
233    clear_block(to, size, vga_attr);
234}
235
236/*
237 * tc_scroll_down
238 *
239 * Scrolls the screen down 'n' character lines.
240 */
241void
242tc_scroll_down(int lines, __unused unsigned int top,
243	       __unused unsigned int bottom)
244{
245    csrpos_t  to;
246    csrpos_t  from;
247    int       size;
248
249    /* move down */
250    to   = ONE_PAGE - ONE_SPACE;
251    from = ONE_PAGE - ( ONE_LINE * lines ) - ONE_SPACE;
252    size = ( ONE_PAGE - ( ONE_LINE * lines ) ) / ONE_SPACE;
253    move_down(from, to, size);
254
255    /* clear top line */
256    to   = 0;
257    size = ( ONE_LINE * lines ) / ONE_SPACE;
258    clear_block(to, size, vga_attr);
259}
260
261/* Default colors for 16-color palette */
262enum {
263    kVGAColorBlack = 0,
264    kVGAColorBlue,
265    kVGAColorGreen,
266    kVGAColorCyan,
267    kVGAColorRed,
268    kVGAColorMagenta,
269    kVGAColorBrown,
270    kVGAColorWhite,
271    kVGAColorGray,
272    kVGAColorLightBlue,
273    kVGAColorLightGreen,
274    kVGAColorLightCyan,
275    kVGAColorLightRed,
276    kVGAColorLightMagenta,
277    kVGAColorLightBrown,
278    kVGAColorBrightWhite
279};
280
281/*
282 * tc_update_color
283 *
284 * Update the foreground / background color.
285 */
286void
287tc_update_color( int color, int fore )
288{
289    unsigned char mask_on, mask_off;
290
291    switch ( color )
292    {
293        case 1:  mask_on = kVGAColorRed;        break;
294        case 3:  mask_on = kVGAColorLightBrown; break;
295        case 4:  mask_on = kVGAColorBlue;       break;
296        case 6:  mask_on = kVGAColorCyan;       break;
297        default: mask_on = color;               break;
298    }
299
300    if ( fore )
301    {
302        mask_off = 0x0f;
303    }
304    else
305    {
306        mask_off = 0xf0;
307        mask_on  <<= 4;
308    }
309
310    vga_attr     = (vga_attr & ~mask_off) | mask_on;
311
312    vga_attr_rev = ( ((vga_attr << 4) & 0xf0) |
313                     ((vga_attr >> 4) & 0x0f) );
314}
315
316/*
317 * tc_show_cursor
318 *
319 * Show the hardware cursor.
320 */
321void
322tc_show_cursor(unsigned int x, unsigned int y)
323{
324    set_cursor_position( XY_TO_CSRPOS(x, y) );
325    set_cursor_enable( TRUE );
326}
327
328/*
329 * tc_hide_cursor
330 *
331 * Hide the hardware cursor.
332 */
333void
334tc_hide_cursor(__unused unsigned int x, __unused unsigned int y)
335{
336    set_cursor_enable( FALSE );
337}
338
339/*
340 * tc_clear_screen
341 *
342 * Clear the entire screen, or a portion of the screen
343 * relative to the current cursor position.
344 */
345void
346tc_clear_screen(unsigned int x, unsigned int y, __unused unsigned int top,
347		__unused unsigned int bottom, int operation)
348{
349    csrpos_t start;
350    int      count;
351
352    switch ( operation )
353    {
354        case 0:   /* To end of screen */
355            start = XY_TO_CSRPOS(x, y);
356            count = ONE_PAGE - start;
357            break;
358        case 1:   /* To start of screen */
359            start = 0;
360            count = XY_TO_CSRPOS(x, y) + ONE_SPACE;
361            break;
362        default:
363        case 2:   /* Whole screen */
364            start = 0;
365            count = ONE_PAGE;
366            break;
367    }
368    clear_block(start, count, vga_attr);
369}
370
371/*
372 * tc_paint_char
373 *
374 * Display a character on screen with the given coordinates,
375 * and attributes.
376 */
377void
378tc_paint_char(unsigned int x, unsigned int y, unsigned char ch, int attrs,
379	      __unused unsigned char ch_previous, __unused int attrs_previous)
380{
381    char my_attr = vga_attr;
382
383    if ( attrs & 4 ) my_attr = vga_attr_rev;
384
385    display_char( XY_TO_CSRPOS(x, y), ch, vga_attr );
386}
387
388/*
389 * tc_enable
390 *
391 * Enable / disable the console.
392 */
393void
394tc_enable(__unused boolean_t enable)
395{
396
397}
398
399/*
400 * tc_initialize
401 *
402 * Must be called before any other exported functions.
403 */
404void
405tc_initialize(struct vc_info * vinfo_p)
406{
407    vinfo_p->v_rows    = vinfo_p->v_height;
408    vinfo_p->v_columns = vinfo_p->v_width;
409
410    vga_init( vinfo_p->v_columns,
411              vinfo_p->v_rows,
412              (unsigned char *) vinfo_p->v_baseaddr);
413}
414