Add better description.
[dragonfly.git] / sys / platform / pc32 / boot / biosboot / 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/i386/boot/biosboot/io.c,v 1.26 1999/08/28 00:43:13 peter Exp $
28  * $DragonFly: src/sys/platform/pc32/boot/biosboot/Attic/io.c,v 1.2 2003/06/17 04:28:34 dillon Exp $
29  */
30
31 #include "boot.h"
32 #include <machine/cpufunc.h>
33 #include <sys/reboot.h>
34
35 #define K_RDWR          0x60            /* keyboard data & cmds (read/write) */
36 #define K_STATUS        0x64            /* keyboard status */
37 #define K_CMD           0x64            /* keybd ctlr command (write-only) */
38
39 #define K_OBUF_FUL      0x01            /* output buffer full */
40 #define K_IBUF_FUL      0x02            /* input buffer full */
41
42 #define KC_CMD_WIN      0xd0            /* read  output port */
43 #define KC_CMD_WOUT     0xd1            /* write output port */
44 #define KB_A20          0xdf            /* enable A20,
45                                            enable output buffer full interrupt
46                                            enable data line
47                                            enable clock line */
48
49
50 static int getchar(int in_buf);
51
52 /*
53  * Gate A20 for high memory
54  */
55 void
56 gateA20(void)
57 {
58 #ifdef  IBM_L40
59         outb(0x92, 0x2);
60 #else   /* !IBM_L40 */
61         while (inb(K_STATUS) & K_IBUF_FUL);
62         while (inb(K_STATUS) & K_OBUF_FUL)
63                 (void)inb(K_RDWR);
64
65         outb(K_CMD, KC_CMD_WOUT);
66         while (inb(K_STATUS) & K_IBUF_FUL);
67         outb(K_RDWR, KB_A20);
68         while (inb(K_STATUS) & K_IBUF_FUL);
69 #endif  /* IBM_L40 */
70 }
71
72 /* printf - only handles %d as decimal, %c as char, %s as string */
73
74 void
75 printf(const char *format, ...)
76 {
77         int *dataptr = (int *)&format;
78         char c;
79
80         dataptr++;
81         while ((c = *format++))
82                 if (c != '%')
83                         putchar(c);
84                 else
85                         switch (c = *format++) {
86                               case 'd': {
87                                       int num = *dataptr++;
88                                       char buf[10], *ptr = buf;
89                                       if (num<0) {
90                                               num = -num;
91                                               putchar('-');
92                                       }
93                                       do
94                                               *ptr++ = '0'+num%10;
95                                       while (num /= 10);
96                                       do
97                                               putchar(*--ptr);
98                                       while (ptr != buf);
99                                       break;
100                               }
101                               case 'x': {
102                                       unsigned int num = *dataptr++, dig;
103                                       char buf[8], *ptr = buf;
104                                       do
105                                               *ptr++ = (dig=(num&0xf)) > 9?
106                                                         'a' + dig - 10 :
107                                                         '0' + dig;
108                                       while (num >>= 4);
109                                       do
110                                               putchar(*--ptr);
111                                       while (ptr != buf);
112                                       break;
113                               }
114                               case 'c': putchar((*dataptr++)&0xff); break;
115                               case 's': {
116                                       char *ptr = (char *)*dataptr++;
117                                       while ((c = *ptr++))
118                                               putchar(c);
119                                       break;
120                               }
121                         }
122 }
123
124 void
125 putchar(int c)
126 {
127         if (c == '\n')
128                 putchar('\r');
129         if (loadflags & RB_DUAL) {
130                 putc(c);
131                 serial_putc(c);
132         } else if (loadflags & RB_SERIAL)
133                 serial_putc(c);
134         else
135                 putc(c);
136 }
137
138 static int
139 getchar(int in_buf)
140 {
141         int c;
142
143 loop:
144         if (loadflags & RB_DUAL) {
145                 if (ischar())
146                         c = getc();
147                 else if (serial_ischar())
148                         c = serial_getc();
149                 else
150                         goto loop;
151         } else if (loadflags & RB_SERIAL)
152                 c = serial_getc();
153         else
154                 c = getc();
155         if (c == '\r')
156                 c = '\n';
157         if (c == '\b') {
158                 if (in_buf != 0) {
159                         putchar('\b');
160                         putchar(' ');
161                 } else {
162                         goto loop;
163                 }
164         }
165         putchar(c);
166         return(c);
167 }
168
169 /*
170  * This routine uses an inb to an unused port, the time to execute that
171  * inb is approximately 1.25uS.  This value is pretty constant across
172  * all CPU's and all buses, with the exception of some PCI implentations
173  * that do not forward this I/O adress to the ISA bus as they know it
174  * is not a valid ISA bus address, those machines execute this inb in
175  * 60 nS :-(.
176  *
177  * XXX this should be converted to use bios_tick.
178  */
179 void
180 delay1ms(void)
181 {
182         int i = 800;
183         while (--i >= 0)
184                 (void)inb(0x84);
185 }
186
187 static __inline int
188 isch(void)
189 {
190         int isc;
191
192         /*
193          * Checking the keyboard has the side effect of enabling clock
194          * interrupts so that bios_tick works.  Check the keyboard to
195          * get this side effect even if we only want the serial status.
196          */
197         isc = ischar();
198
199         if (loadflags & RB_DUAL) {
200                 if (isc != 0)
201                         return (isc);
202         } else if (!(loadflags & RB_SERIAL))
203                 return (isc);
204         return (serial_ischar());
205 }
206
207 static __inline unsigned
208 pword(unsigned physaddr)
209 {
210         unsigned result;
211
212         /*
213          * Give the fs prefix separately because gas omits it for
214          * "movl %fs:0x46c, %eax".
215          */
216         __asm __volatile("fs; movl %1, %0" : "=r" (result)
217                          : "m" (*(unsigned *)physaddr));
218         return (result);
219 }
220
221 int
222 gets(char *buf)
223 {
224 #define bios_tick               pword(0x46c)
225 #define BIOS_TICK_MS            55
226         unsigned initial_bios_tick;
227         char *ptr=buf;
228
229 #if BOOTWAIT
230         for (initial_bios_tick = bios_tick;
231              bios_tick - initial_bios_tick < BOOTWAIT / BIOS_TICK_MS;)
232 #endif
233                 if (isch())
234                         for (;;) {
235                                 switch(*ptr = getchar(ptr - buf) & 0xff) {
236                                       case '\n':
237                                       case '\r':
238                                         *ptr = '\0';
239                                         return 1;
240                                       case '\b':
241                                         if (ptr > buf) ptr--;
242                                         continue;
243                                       default:
244                                         ptr++;
245                                 }
246 #if TIMEOUT + 0
247 #if !BOOTWAIT
248 #error "TIMEOUT without BOOTWAIT"
249 #endif
250                                 for (initial_bios_tick = bios_tick;;) {
251                                         if (isch())
252                                                 break;
253                                         if (bios_tick - initial_bios_tick >=
254                                             TIMEOUT / BIOS_TICK_MS)
255                                         return 0;
256                                 }
257 #endif
258                         }
259         return 0;
260 }
261
262 int
263 strcmp(const char *s1, const char *s2)
264 {
265         while (*s1 == *s2) {
266                 if (!*s1++)
267                         return 0;
268                 s2++;
269         }
270         return 1;
271 }
272
273 #ifdef CDBOOT
274 int
275 strcasecmp(const char *s1, const char *s2)
276 {
277         /*
278          * We only consider ASCII chars and don't anticipate
279          * control characters (they are invalid in filenames
280          * anyway).
281          */
282         while ((*s1 & 0x5f) == (*s2 & 0x5f)) {
283                 if (!*s1++)
284                         return 0;
285                 s2++;
286         }
287         return 1;
288 }
289 #endif /* !CDBOOT */
290
291 void
292 bcopy(const void *from, void *to, size_t len)
293 {
294         char *fp = (char *)from;
295         char *tp = (char *)to;
296
297         while (len-- > 0)
298                 *tp++ = *fp++;
299 }
300
301 /* To quote Ken: "You are not expected to understand this." :) */
302
303 void
304 twiddle(void)
305 {
306         putchar((char)tw_chars);
307         tw_chars = (tw_chars >> 8) | ((tw_chars & (unsigned long)0xFF) << 24);
308         putchar('\b');
309 }