1/* hercules.c - hercules console interface */
2/*
3 *  GRUB  --  GRand Unified Bootloader
4 *  Copyright (C) 2001,2002  Free Software Foundation, Inc.
5 *
6 *  This program is free software; you can redistribute it and/or modify
7 *  it under the terms of the GNU General Public License as published by
8 *  the Free Software Foundation; either version 2 of the License, or
9 *  (at your option) any later version.
10 *
11 *  This program is distributed in the hope that it will be useful,
12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 *  GNU General Public License for more details.
15 *
16 *  You should have received a copy of the GNU General Public License
17 *  along with this program; if not, write to the Free Software
18 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21#ifdef SUPPORT_HERCULES
22
23#include <shared.h>
24#include <hercules.h>
25#include <term.h>
26
27/* The position of the cursor.  */
28static int herc_x;
29static int herc_y;
30
31static int herc_standard_color = A_NORMAL;
32static int herc_normal_color = A_NORMAL;
33static int herc_highlight_color = A_REVERSE;
34static int herc_current_color = A_NORMAL;
35static color_state herc_color_state = COLOR_STATE_STANDARD;
36static int herc_cursor_state = 1;
37
38/* Write a byte to a port.  */
39static inline void
40outb (unsigned short port, unsigned char value)
41{
42  asm volatile ("outb	%b0, %w1" : : "a" (value), "Nd" (port));
43}
44
45static void
46herc_set_cursor (void)
47{
48  unsigned offset = herc_y * HERCULES_WIDTH + herc_x;
49
50  outb (HERCULES_INDEX_REG, 0x0f);
51  outb (0x80, 0);
52  outb (HERCULES_DATA_REG, offset & 0xFF);
53  outb (0x80, 0);
54
55  outb (HERCULES_INDEX_REG, 0x0e);
56  outb (0x80, 0);
57  outb (HERCULES_DATA_REG, offset >> 8);
58  outb (0x80, 0);
59}
60
61void
62hercules_putchar (int c)
63{
64  switch (c)
65    {
66    case '\b':
67      if (herc_x > 0)
68	herc_x--;
69      break;
70
71    case '\n':
72      herc_y++;
73      break;
74
75    case '\r':
76      herc_x = 0;
77      break;
78
79    case '\a':
80      break;
81
82    default:
83      {
84	volatile unsigned short *video
85	  = (unsigned short *) HERCULES_VIDEO_ADDR;
86
87	video[herc_y * HERCULES_WIDTH + herc_x]
88	  = (herc_current_color << 8) | c;
89	herc_x++;
90	if (herc_x >= HERCULES_WIDTH)
91	  {
92	    herc_x = 0;
93	    herc_y++;
94	  }
95      }
96      break;
97    }
98
99  if (herc_y >= HERCULES_HEIGHT)
100    {
101      volatile unsigned long *video = (unsigned long *) HERCULES_VIDEO_ADDR;
102      int i;
103
104      herc_y = HERCULES_HEIGHT - 1;
105      grub_memmove ((char *) HERCULES_VIDEO_ADDR,
106		    (char *) HERCULES_VIDEO_ADDR + HERCULES_WIDTH * 2,
107		    HERCULES_WIDTH * (HERCULES_HEIGHT - 1) * 2);
108      for (i = HERCULES_WIDTH * (HERCULES_HEIGHT - 1) / 2;
109	   i < HERCULES_WIDTH * HERCULES_HEIGHT / 2;
110	   i++)
111	video[i] = 0x07200720;
112    }
113}
114
115void
116hercules_cls (void)
117{
118  int i;
119  volatile unsigned long *video = (unsigned long *) HERCULES_VIDEO_ADDR;
120
121  for (i = 0; i < HERCULES_WIDTH * HERCULES_HEIGHT / 2; i++)
122    video[i] = 0x07200720;
123
124  herc_x = herc_y = 0;
125  herc_set_cursor ();
126}
127
128int
129hercules_getxy (void)
130{
131  return (herc_x << 8) | herc_y;
132}
133
134void
135hercules_gotoxy (int x, int y)
136{
137  herc_x = x;
138  herc_y = y;
139  herc_set_cursor ();
140}
141
142void
143hercules_setcolorstate (color_state state)
144{
145  switch (state) {
146    case COLOR_STATE_STANDARD:
147      herc_current_color = herc_standard_color;
148      break;
149    case COLOR_STATE_NORMAL:
150      herc_current_color = herc_normal_color;
151      break;
152    case COLOR_STATE_HIGHLIGHT:
153      herc_current_color = herc_highlight_color;
154      break;
155    default:
156      herc_current_color = herc_standard_color;
157      break;
158  }
159
160  herc_color_state = state;
161}
162
163void
164hercules_setcolor (int normal_color, int highlight_color)
165{
166  herc_normal_color = normal_color;
167  herc_highlight_color = highlight_color;
168
169  hercules_setcolorstate (herc_color_state);
170}
171
172int
173hercules_setcursor (int on)
174{
175  int old_state = herc_cursor_state;
176
177  outb (HERCULES_INDEX_REG, 0x0a);
178  outb (0x80, 0);
179  outb (HERCULES_DATA_REG, on ? 0 : (1 << 5));
180  outb (0x80, 0);
181  herc_cursor_state = on;
182
183  return old_state;
184}
185
186#endif /* SUPPORT_HERCULES */
187