blob: cd894573828910bea45204b33215dbc6bdcfbcd2 [file] [log] [blame]
wdenkabda5ca2003-05-31 18:35:21 +00001/*
2 * (C) Copyright 2002
3 * Daniel Engström, Omicron Ceti AB, daniel@omicron.se
4 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 */
23
wdenk57b2d802003-06-27 21:31:46 +000024#include <common.h>
25#include <pci.h>
wdenkabda5ca2003-05-31 18:35:21 +000026#include <devices.h>
27#include <i8042.h>
wdenk57b2d802003-06-27 21:31:46 +000028#include <asm/ptrace.h>
29#include <asm/realmode.h>
30#include <asm/io.h>
31#include <asm/pci.h>
wdenkabda5ca2003-05-31 18:35:21 +000032
33
34/* basic textmode I/O from linux kernel */
35static char *vidmem = (char *)0xb8000;
36static int vidport;
37static int lines, cols;
38static int orig_x, orig_y;
39
40static void beep(int dur)
41{
42 int i;
wdenk57b2d802003-06-27 21:31:46 +000043
wdenkabda5ca2003-05-31 18:35:21 +000044 outb_p(3, 0x61);
45 for (i=0;i<10*dur;i++) {
46 udelay(1000);
47 }
48 outb_p(0, 0x61);
49}
50
51static void scroll(void)
52{
53 int i;
54
55 memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 );
56 for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 )
57 vidmem[i] = ' ';
58}
59
60static void __video_putc(const char c, int *x, int *y)
61{
62 if (c == '\n') {
wdenk57b2d802003-06-27 21:31:46 +000063 (*x) = 0;
wdenkabda5ca2003-05-31 18:35:21 +000064 if ( ++(*y) >= lines ) {
65 scroll();
66 (*y)--;
67 }
wdenk57b2d802003-06-27 21:31:46 +000068 } else if (c == '\b') {
wdenkabda5ca2003-05-31 18:35:21 +000069 if ((*x) != 0) {
70 --(*x);
wdenk57b2d802003-06-27 21:31:46 +000071 vidmem [ ( (*x) + cols * (*y) ) * 2 ] = ' ';
wdenkabda5ca2003-05-31 18:35:21 +000072 }
wdenk57b2d802003-06-27 21:31:46 +000073 } else if (c == '\r') {
wdenkabda5ca2003-05-31 18:35:21 +000074 (*x) = 0;
wdenk57b2d802003-06-27 21:31:46 +000075
76 } else if (c == '\a') {
wdenkabda5ca2003-05-31 18:35:21 +000077 beep(3);
wdenk57b2d802003-06-27 21:31:46 +000078
79 } else if (c == '\t') {
wdenkabda5ca2003-05-31 18:35:21 +000080 __video_putc(' ', x, y);
81 __video_putc(' ', x, y);
82 __video_putc(' ', x, y);
83 __video_putc(' ', x, y);
84 __video_putc(' ', x, y);
85 __video_putc(' ', x, y);
86 __video_putc(' ', x, y);
87 __video_putc(' ', x, y);
wdenk57b2d802003-06-27 21:31:46 +000088 } else if (c == '\v') {
wdenkabda5ca2003-05-31 18:35:21 +000089 switch ((*x) % 8) {
90 case 0:
91 __video_putc(' ', x, y);
92 case 7:
93 __video_putc(' ', x, y);
94 case 6:
95 __video_putc(' ', x, y);
96 case 5:
97 __video_putc(' ', x, y);
98 case 4:
99 __video_putc(' ', x, y);
100 case 3:
101 __video_putc(' ', x, y);
102 case 2:
103 __video_putc(' ', x, y);
104 case 1:
105 __video_putc(' ', x, y);
106 }
wdenk57b2d802003-06-27 21:31:46 +0000107 } else if (c == '\f') {
wdenkabda5ca2003-05-31 18:35:21 +0000108 int i;
109 for (i=0;i<lines*cols*2;i+=2) {
110 vidmem[i] = 0;
111 }
112 (*x) = 0;
113 (*y) = 0;
114 } else {
wdenk57b2d802003-06-27 21:31:46 +0000115 vidmem [ ( (*x) + cols * (*y) ) * 2 ] = c;
wdenkabda5ca2003-05-31 18:35:21 +0000116 if ( ++(*x) >= cols ) {
117 (*x) = 0;
118 if ( ++(*y) >= lines ) {
119 scroll();
120 (*y)--;
121 }
122 }
123 }
124}
125
126static void video_putc(const char c)
127{
128 int x,y,pos;
wdenk57b2d802003-06-27 21:31:46 +0000129
wdenkabda5ca2003-05-31 18:35:21 +0000130 x = orig_x;
131 y = orig_y;
wdenk57b2d802003-06-27 21:31:46 +0000132
wdenkabda5ca2003-05-31 18:35:21 +0000133 __video_putc(c, &x, &y);
134
135 orig_x = x;
136 orig_y = y;
wdenk57b2d802003-06-27 21:31:46 +0000137
wdenkabda5ca2003-05-31 18:35:21 +0000138 pos = (x + cols * y) * 2; /* Update cursor position */
139 outb_p(14, vidport);
140 outb_p(0xff & (pos >> 9), vidport+1);
141 outb_p(15, vidport);
142 outb_p(0xff & (pos >> 1), vidport+1);
143}
144
145static void video_puts(const char *s)
146{
147 int x,y,pos;
148 char c;
149
150 x = orig_x;
151 y = orig_y;
152
153 while ( ( c = *s++ ) != '\0' ) {
154 __video_putc(c, &x, &y);
155 }
156
157 orig_x = x;
158 orig_y = y;
159
160 pos = (x + cols * y) * 2; /* Update cursor position */
161 outb_p(14, vidport);
162 outb_p(0xff & (pos >> 9), vidport+1);
163 outb_p(15, vidport);
164 outb_p(0xff & (pos >> 1), vidport+1);
165}
166
167int video_init(void)
168{
169 u16 pos;
wdenk57b2d802003-06-27 21:31:46 +0000170
wdenkabda5ca2003-05-31 18:35:21 +0000171 static device_t vga_dev;
172 static device_t kbd_dev;
wdenk57b2d802003-06-27 21:31:46 +0000173
wdenkabda5ca2003-05-31 18:35:21 +0000174 vidmem = (char *) 0xb8000;
175 vidport = 0x3d4;
176
177 lines = 25;
178 cols = 80;
wdenk57b2d802003-06-27 21:31:46 +0000179
wdenkabda5ca2003-05-31 18:35:21 +0000180 outb_p(14, vidport);
181 pos = inb_p(vidport+1);
182 pos <<= 8;
183 outb_p(15, vidport);
184 pos |= inb_p(vidport+1);
wdenk57b2d802003-06-27 21:31:46 +0000185
wdenkabda5ca2003-05-31 18:35:21 +0000186 orig_x = pos%cols;
187 orig_y = pos/cols;
188
wdenk57b2d802003-06-27 21:31:46 +0000189#if 0
wdenkabda5ca2003-05-31 18:35:21 +0000190 printf("pos %x %d %d\n", pos, orig_x, orig_y);
wdenk57b2d802003-06-27 21:31:46 +0000191#endif
wdenkabda5ca2003-05-31 18:35:21 +0000192 if (orig_y > lines) {
193 orig_x = orig_y =0;
194 }
wdenk57b2d802003-06-27 21:31:46 +0000195
196
wdenkabda5ca2003-05-31 18:35:21 +0000197 memset(&vga_dev, 0, sizeof(vga_dev));
wdenk57b2d802003-06-27 21:31:46 +0000198 strcpy(vga_dev.name, "vga");
199 vga_dev.ext = 0;
200 vga_dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_SYSTEM;
201 vga_dev.putc = video_putc; /* 'putc' function */
202 vga_dev.puts = video_puts; /* 'puts' function */
203 vga_dev.tstc = NULL; /* 'tstc' function */
204 vga_dev.getc = NULL; /* 'getc' function */
wdenkabda5ca2003-05-31 18:35:21 +0000205
wdenk57b2d802003-06-27 21:31:46 +0000206 if (device_register(&vga_dev) == 0) {
207 return 1;
wdenkabda5ca2003-05-31 18:35:21 +0000208 }
wdenk57b2d802003-06-27 21:31:46 +0000209
wdenkabda5ca2003-05-31 18:35:21 +0000210 if (i8042_kbd_init()) {
211 return 1;
212 }
wdenk57b2d802003-06-27 21:31:46 +0000213
wdenkabda5ca2003-05-31 18:35:21 +0000214 memset(&kbd_dev, 0, sizeof(kbd_dev));
wdenk57b2d802003-06-27 21:31:46 +0000215 strcpy(kbd_dev.name, "kbd");
216 kbd_dev.ext = 0;
217 kbd_dev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
218 kbd_dev.putc = NULL; /* 'putc' function */
219 kbd_dev.puts = NULL; /* 'puts' function */
220 kbd_dev.tstc = i8042_tstc; /* 'tstc' function */
221 kbd_dev.getc = i8042_getc; /* 'getc' function */
wdenkabda5ca2003-05-31 18:35:21 +0000222
wdenk57b2d802003-06-27 21:31:46 +0000223 if (device_register(&kbd_dev) == 0) {
224 return 1;
wdenkabda5ca2003-05-31 18:35:21 +0000225 }
226 return 0;
227}
228
229
wdenk57b2d802003-06-27 21:31:46 +0000230int drv_video_init(void)
wdenkabda5ca2003-05-31 18:35:21 +0000231{
232 if (video_bios_init()) {
233 return 1;
234 }
wdenk57b2d802003-06-27 21:31:46 +0000235
236 return video_init();
wdenkabda5ca2003-05-31 18:35:21 +0000237}