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