Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / boot / pc98 / boot2 / io.c
1 /*
2  * Mach Operating System
3  * Copyright (c) 1992, 1991 Carnegie Mellon University
4  * All Rights Reserved.
5  *
6  * Permission to use, copy, modify and distribute this software and its
7  * documentation is hereby granted, provided that both the copyright
8  * notice and this permission notice appear in all copies of the
9  * software, derivative works or modified versions, and any portions
10  * thereof, and that both notices appear in supporting documentation.
11  *
12  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15  *
16  * Carnegie Mellon requests users of this software to return to
17  *
18  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
19  *  School of Computer Science
20  *  Carnegie Mellon University
21  *  Pittsburgh PA 15213-3890
22  *
23  * any improvements or extensions that they make and grant Carnegie Mellon
24  * the rights to redistribute these changes.
25  *
26  *      from: Mach, Revision 2.2  92/04/04  11:35:57  rpd
27  * $FreeBSD: src/sys/boot/pc98/boot2/io.c,v 1.2.2.1 2001/10/07 13:22:38 nyan Exp $
28  */
29
30 #include "boot.h"
31 #include <machine/cpufunc.h>
32 #include <sys/reboot.h>
33 #ifdef PC98
34 #include <pc98/pc98/pc98.h>
35 #endif
36
37
38 static int getchar(int in_buf);
39
40 /*
41  * Gate A20 for high memory
42  */
43 void
44 gateA20(void)
45 {
46         outb(0xf2, 0x00);
47         outb(0xf6, 0x02);
48 }
49
50 /* printf - only handles %d as decimal, %c as char, %s as string */
51
52 void
53 printf(const char *format, ...)
54 {
55         int *dataptr = (int *)&format;
56         char c;
57
58         dataptr++;
59         while ((c = *format++))
60                 if (c != '%')
61                         putchar(c);
62                 else
63                         switch (c = *format++) {
64                               case 'd': {
65                                       int num = *dataptr++;
66                                       char buf[10], *ptr = buf;
67                                       if (num<0) {
68                                               num = -num;
69                                               putchar('-');
70                                       }
71                                       do
72                                               *ptr++ = '0'+num%10;
73                                       while (num /= 10);
74                                       do
75                                               putchar(*--ptr);
76                                       while (ptr != buf);
77                                       break;
78                               }
79                               case 'x': {
80                                       unsigned int num = *dataptr++, dig;
81                                       char buf[8], *ptr = buf;
82                                       do
83                                               *ptr++ = (dig=(num&0xf)) > 9?
84                                                         'a' + dig - 10 :
85                                                         '0' + dig;
86                                       while (num >>= 4);
87                                       do
88                                               putchar(*--ptr);
89                                       while (ptr != buf);
90                                       break;
91                               }
92                               case 'c': putchar((*dataptr++)&0xff); break;
93                               case 's': {
94                                       char *ptr = (char *)*dataptr++;
95                                       while ((c = *ptr++))
96                                               putchar(c);
97                                       break;
98                               }
99                         }
100 }
101
102 void
103 putchar(int c)
104 {
105         if (c == '\n')
106                 putchar('\r');
107         if (loadflags & RB_DUAL) {
108                 putc(c);
109                 serial_putc(c);
110         } else if (loadflags & RB_SERIAL)
111                 serial_putc(c);
112         else
113                 putc(c);
114 }
115
116 static int
117 getchar(int in_buf)
118 {
119         int c;
120
121 loop:
122         if (loadflags & RB_DUAL) {
123                 if (ischar())
124                         c = getc();
125                 else if (serial_ischar())
126                         c = serial_getc();
127                 else
128                         goto loop;
129         } else if (loadflags & RB_SERIAL)
130                 c = serial_getc();
131         else
132                 c = getc();
133         if (c == '\r')
134                 c = '\n';
135         if (c == '\b') {
136                 if (in_buf != 0) {
137                         putchar('\b');
138                         putchar(' ');
139                 } else {
140                         goto loop;
141                 }
142         }
143         putchar(c);
144         return(c);
145 }
146
147 /*
148  * This routine uses an inb to an unused port, the time to execute that
149  * inb is approximately 1.25uS.  This value is pretty constant across
150  * all CPU's and all buses, with the exception of some PCI implentations
151  * that do not forward this I/O address to the ISA bus as they know it
152  * is not a valid ISA bus address, those machines execute this inb in
153  * 60 nS :-(.
154  *
155  * XXX this should be converted to use bios_tick.
156  */
157 void
158 delay1ms(void)
159 {
160 #ifdef PC98
161         int i = 800;
162         while (--i >= 0)
163             (void)outb(0x5f,0);         /* about 600ns */
164 #else
165         int i = 800;
166         while (--i >= 0)
167                 (void)inb(0x84);
168 #endif
169 }
170
171 static __inline int
172 isch(void)
173 {
174         int isc;
175
176         /*
177          * Checking the keyboard has the side effect of enabling clock
178          * interrupts so that bios_tick works.  Check the keyboard to
179          * get this side effect even if we only want the serial status.
180          */
181         isc = ischar();
182
183         if (loadflags & RB_DUAL) {
184                 if (isc != 0)
185                         return (isc);
186         } else if (!(loadflags & RB_SERIAL))
187                 return (isc);
188         return (serial_ischar());
189 }
190
191 static __inline unsigned
192 pword(unsigned physaddr)
193 {
194 #ifdef PC98
195         static int counter = 0;
196         int i;
197
198         for (i = 0; i < 512; i++)
199                 (void)outb(0x5f, 0);
200
201         return (counter++);
202 #else
203         unsigned result;
204
205         /*
206          * Give the fs prefix separately because gas omits it for
207          * "movl %fs:0x46c, %eax".
208          */
209         __asm __volatile("fs; movl %1, %0" : "=r" (result)
210                          : "m" (*(unsigned *)physaddr));
211         return (result);
212 #endif
213 }
214
215 int
216 gets(char *buf)
217 {
218 #define bios_tick               pword(0x46c)
219 #ifdef PC98
220 #define BIOS_TICK_MS            1
221 #else
222 #define BIOS_TICK_MS            55
223 #endif
224         unsigned initial_bios_tick;
225         char *ptr=buf;
226
227 #if BOOTWAIT
228         for (initial_bios_tick = bios_tick;
229              bios_tick - initial_bios_tick < BOOTWAIT / BIOS_TICK_MS;)
230 #endif
231                 if (isch())
232                         for (;;) {
233                                 switch(*ptr = getchar(ptr - buf) & 0xff) {
234                                       case '\n':
235                                       case '\r':
236                                         *ptr = '\0';
237                                         return 1;
238                                       case '\b':
239                                         if (ptr > buf) ptr--;
240                                         continue;
241                                       default:
242                                         ptr++;
243                                 }
244 #if TIMEOUT + 0
245 #if !BOOTWAIT
246 #error "TIMEOUT without BOOTWAIT"
247 #endif
248                                 for (initial_bios_tick = bios_tick;;) {
249                                         if (isch())
250                                                 break;
251                                         if (bios_tick - initial_bios_tick >=
252                                             TIMEOUT / BIOS_TICK_MS)
253                                         return 0;
254                                 }
255 #endif
256                         }
257         return 0;
258 }
259
260 int
261 strcmp(const char *s1, const char *s2)
262 {
263         while (*s1 == *s2) {
264                 if (!*s1++)
265                         return 0;
266                 s2++;
267         }
268         return 1;
269 }
270
271 #ifdef CDBOOT
272 int
273 strcasecmp(const char *s1, const char *s2)
274 {
275         /*
276          * We only consider ASCII chars and don't anticipate
277          * control characters (they are invalid in filenames
278          * anyway).
279          */
280         while ((*s1 & 0x5f) == (*s2 & 0x5f)) {
281                 if (!*s1++)
282                         return 0;
283                 s2++;
284         }
285         return 1;
286 }
287 #endif /* !CDBOOT */
288
289 void
290 bcopy(const void *from, void *to, size_t len)
291 {
292         char *fp = (char *)from;
293         char *tp = (char *)to;
294
295         while (len-- > 0)
296                 *tp++ = *fp++;
297 }
298
299 /* To quote Ken: "You are not expected to understand this." :) */
300
301 void
302 twiddle(void)
303 {
304         putchar((char)tw_chars);
305         tw_chars = (tw_chars >> 8) | ((tw_chars & (unsigned long)0xFF) << 24);
306         putchar('\b');
307 }
308
309 static unsigned short *Crtat = (unsigned short *)0;
310 static int row;
311 static int col;
312
313 void putc(int c)
314 {
315         static unsigned short *crtat;
316         unsigned char sys_type;
317         unsigned short *cp;
318         int i, pos;
319
320         if (Crtat == 0) {
321                 sys_type = *(unsigned char *)V(0xA1501);
322                 if (sys_type & 0x08) {
323                         Crtat = (unsigned short *)V(0xE0000);
324                         crtat = Crtat;
325                         row = 31;
326                         col = 80;
327                 } else {
328                         Crtat = (unsigned short *)V(0xA0000);
329                         crtat = Crtat;
330                         row = 25;
331                         col = 80;
332                 }
333         }
334
335         switch(c) {
336         case '\t':
337                 do {
338                         putc(' ');
339                 } while ((int)crtat % 16);
340                 break;
341         case '\b':
342                 crtat--;
343                 break;
344         case '\r':
345                 crtat -= (crtat - Crtat) % col;
346                 break;
347         case '\n':
348                 crtat += col;
349                 break;
350         default:
351                 *crtat = (c == 0x5c ? 0xfc : c);
352                 *(crtat++ + 0x1000) = 0xe1;
353                 break;
354         }
355
356         if (crtat >= Crtat + col * row) {
357                 cp = Crtat;
358                 for (i = 1; i < row; i++) {
359                         bcopy((void *)(cp+col), (void *)cp, col*2);
360                         cp += col;
361                 }
362                 for (i = 0; i < col; i++) {
363                         *cp++ = ' ';
364                 }
365                 crtat -= col;
366         }
367         pos = crtat - Crtat;
368         while((inb(0x60) & 0x04) == 0) {}
369         outb(0x62, 0x49);
370         outb(0x60, pos & 0xff);
371         outb(0x60, pos >> 8);
372 }
373
374 void machine_check(void)
375 {
376         int     ret;
377         int     i;
378         int     data = 0;
379         u_char epson_machine_id = *(unsigned char *)V(0xA1624);
380         
381         /* PC98_SYSTEM_PARAMETER(0x501) */
382         ret = ((*(unsigned char*)V(0xA1501)) & 0x08) >> 3;
383
384         /* Wait V-SYNC */
385         while (inb(0x60) & 0x20) {}
386         while (!(inb(0x60) & 0x20)) {}
387
388         /* ANK 'A' font */
389         outb(0xa1, 0x00);
390         outb(0xa3, 0x41);
391
392         /* M_NORMAL, use CG window (all NEC OK)  */
393         /* sum */
394         for (i = 0; i < 4; i++) {
395                 data += *((unsigned long*)V(0xA4000) + i);/* 0xa4000 */
396         }
397         if (data == 0x6efc58fc) { /* DA data */
398                 ret |= M_NEC_PC98;
399         } else {
400                 ret |= M_EPSON_PC98;
401         }
402         ret |= (inb(0x42) & 0x20) ? M_8M : 0;
403
404         /* PC98_SYSTEM_PARAMETER(0x400) */
405         if ((*(unsigned char*)V(0xA1400)) & 0x80) {
406                 ret |= M_NOTE;
407         }
408         if (ret & M_NEC_PC98) {
409                 /* PC98_SYSTEM_PARAMETER(0x458) */
410                 if ((*(unsigned char*)V(0xA1458)) & 0x80) {
411                         ret |= M_H98;
412                 } else {
413                         ret |= M_NOT_H98;
414                 }
415         } else {
416                 ret |= M_NOT_H98;
417                 switch (epson_machine_id) {
418                 case 0x20:      /* note A */
419                 case 0x22:      /* note W */
420                 case 0x27:      /* note AE */
421                 case 0x2a:      /* note WR */
422                         ret |= M_NOTE;
423                         break;
424                 default:
425                             break;
426                 }
427         }
428         (*(unsigned long *)V(0xA1620)) = ret;
429 }