| /* |
| * GRUB -- GRand Unified Bootloader |
| * Copyright (C) 2000 Free Software Foundation, Inc. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| */ |
| |
| /* Based on "src/misc.c" in etherboot-4.5.8. */ |
| |
| /************************************************************************** |
| MISC Support Routines |
| **************************************************************************/ |
| |
| #include "etherboot.h" |
| |
| /************************************************************************** |
| SLEEP |
| **************************************************************************/ |
| void sleep(int secs) |
| { |
| unsigned long tmo; |
| |
| for (tmo = currticks()+secs*TICKS_PER_SEC; currticks() < tmo; ) |
| /* Nothing */; |
| } |
| |
| /************************************************************************** |
| TWIDDLE |
| **************************************************************************/ |
| void twiddle() |
| { |
| static unsigned long lastticks = 0; |
| static int count=0; |
| static char tiddles[]="-\\|/"; |
| unsigned long ticks; |
| if ((ticks = currticks()) == lastticks) |
| return; |
| lastticks = ticks; |
| putchar(tiddles[(count++)&3]); |
| putchar('\b'); |
| } |
| |
| #ifndef GRUB |
| /************************************************************************** |
| STRCASECMP (not entirely correct, but this will do for our purposes) |
| **************************************************************************/ |
| int strcasecmp(a,b) |
| char *a, *b; |
| { |
| while (*a && *b && (*a & ~0x20) == (*b & ~0x20)) {a++; b++; } |
| return((*a & ~0x20) - (*b & ~0x20)); |
| } |
| |
| /************************************************************************** |
| PRINTF and friends |
| |
| Formats: |
| %X - 4 byte ASCII (8 hex digits) |
| %x - 2 byte ASCII (4 hex digits) |
| %b - 1 byte ASCII (2 hex digits) |
| %d - decimal (also %i) |
| %c - ASCII char |
| %s - ASCII string |
| %I - Internet address in x.x.x.x notation |
| **************************************************************************/ |
| static char hex[]="0123456789ABCDEF"; |
| static char *do_printf(char *buf, const char *fmt, const int *dp) |
| { |
| register char *p; |
| char tmp[16]; |
| while (*fmt) { |
| if (*fmt == '%') { /* switch() uses more space */ |
| fmt++; |
| |
| if (*fmt == 'X') { |
| const long *lp = (const long *)dp; |
| register long h = *lp++; |
| dp = (const int *)lp; |
| *(buf++) = hex[(h>>28)& 0x0F]; |
| *(buf++) = hex[(h>>24)& 0x0F]; |
| *(buf++) = hex[(h>>20)& 0x0F]; |
| *(buf++) = hex[(h>>16)& 0x0F]; |
| *(buf++) = hex[(h>>12)& 0x0F]; |
| *(buf++) = hex[(h>>8)& 0x0F]; |
| *(buf++) = hex[(h>>4)& 0x0F]; |
| *(buf++) = hex[h& 0x0F]; |
| } |
| if (*fmt == 'x') { |
| register int h = *(dp++); |
| *(buf++) = hex[(h>>12)& 0x0F]; |
| *(buf++) = hex[(h>>8)& 0x0F]; |
| *(buf++) = hex[(h>>4)& 0x0F]; |
| *(buf++) = hex[h& 0x0F]; |
| } |
| if (*fmt == 'b') { |
| register int h = *(dp++); |
| *(buf++) = hex[(h>>4)& 0x0F]; |
| *(buf++) = hex[h& 0x0F]; |
| } |
| if ((*fmt == 'd') || (*fmt == 'i')) { |
| register int dec = *(dp++); |
| p = tmp; |
| if (dec < 0) { |
| *(buf++) = '-'; |
| dec = -dec; |
| } |
| do { |
| *(p++) = '0' + (dec%10); |
| dec = dec/10; |
| } while(dec); |
| while ((--p) >= tmp) *(buf++) = *p; |
| } |
| if (*fmt == 'I') { |
| union { |
| long l; |
| unsigned char c[4]; |
| } u; |
| const long *lp = (const long *)dp; |
| u.l = *lp++; |
| dp = (const int *)lp; |
| buf = sprintf(buf,"%d.%d.%d.%d", |
| u.c[0], u.c[1], u.c[2], u.c[3]); |
| } |
| if (*fmt == 'c') |
| *(buf++) = *(dp++); |
| if (*fmt == 's') { |
| p = (char *)*dp++; |
| while (*p) *(buf++) = *p++; |
| } |
| } else *(buf++) = *fmt; |
| fmt++; |
| } |
| *buf = 0; |
| return(buf); |
| } |
| |
| char *sprintf(char *buf, const char *fmt, ...) |
| { |
| return do_printf(buf, fmt, ((const int *)&fmt)+1); |
| } |
| |
| void printf(const char *fmt, ...) |
| { |
| char buf[120],*p; |
| |
| p = buf; |
| do_printf(buf, fmt, ((const int *)&fmt)+1); |
| while (*p) putchar(*p++); |
| } |
| #endif /* ! GRUB */ |
| |
| #if defined(IMAGE_MENU) || defined(GRUB) |
| /************************************************************************** |
| INET_ATON - Convert an ascii x.x.x.x to binary form |
| **************************************************************************/ |
| int inet_aton(char *p, in_addr *i) |
| { |
| unsigned long ip = 0; |
| int val; |
| if (((val = getdec(&p)) < 0) || (val > 255)) return(0); |
| if (*p != '.') return(0); |
| p++; |
| ip = val; |
| if (((val = getdec(&p)) < 0) || (val > 255)) return(0); |
| if (*p != '.') return(0); |
| p++; |
| ip = (ip << 8) | val; |
| if (((val = getdec(&p)) < 0) || (val > 255)) return(0); |
| if (*p != '.') return(0); |
| p++; |
| ip = (ip << 8) | val; |
| if (((val = getdec(&p)) < 0) || (val > 255)) return(0); |
| i->s_addr = htonl((ip << 8) | val); |
| return(1); |
| } |
| #endif /* IMAGE_MENU || GRUB */ |
| |
| int getdec(char **ptr) |
| { |
| char *p = *ptr; |
| int ret=0; |
| if ((*p < '0') || (*p > '9')) return(-1); |
| while ((*p >= '0') && (*p <= '9')) { |
| ret = ret*10 + (*p - '0'); |
| p++; |
| } |
| *ptr = p; |
| return(ret); |
| } |
| |
| #ifndef GRUB |
| #define K_RDWR 0x60 /* keyboard data & cmds (read/write) */ |
| #define K_STATUS 0x64 /* keyboard status */ |
| #define K_CMD 0x64 /* keybd ctlr command (write-only) */ |
| |
| #define K_OBUF_FUL 0x01 /* output buffer full */ |
| #define K_IBUF_FUL 0x02 /* input buffer full */ |
| |
| #define KC_CMD_WIN 0xd0 /* read output port */ |
| #define KC_CMD_WOUT 0xd1 /* write output port */ |
| #define KB_SET_A20 0xdf /* enable A20, |
| enable output buffer full interrupt |
| enable data line |
| disable clock line */ |
| #define KB_UNSET_A20 0xdd /* enable A20, |
| enable output buffer full interrupt |
| enable data line |
| disable clock line */ |
| #ifndef IBM_L40 |
| static void empty_8042(void) |
| { |
| unsigned long time; |
| char st; |
| |
| slowdownio(); |
| time = currticks() + TICKS_PER_SEC; /* max wait of 1 second */ |
| while ((((st = inb(K_CMD)) & K_OBUF_FUL) || |
| (st & K_IBUF_FUL)) && |
| currticks() < time) |
| inb(K_RDWR); |
| } |
| #endif IBM_L40 |
| |
| /* |
| * Gate A20 for high memory |
| */ |
| void gateA20_set(void) |
| { |
| #ifdef IBM_L40 |
| outb(0x2, 0x92); |
| #else /* IBM_L40 */ |
| empty_8042(); |
| outb(KC_CMD_WOUT, K_CMD); |
| empty_8042(); |
| outb(KB_SET_A20, K_RDWR); |
| empty_8042(); |
| #endif /* IBM_L40 */ |
| } |
| |
| #ifdef TAGGED_IMAGE |
| /* |
| * Unset Gate A20 for high memory - some operating systems (mainly old 16 bit |
| * ones) don't expect it to be set by the boot loader. |
| */ |
| void gateA20_unset(void) |
| { |
| #ifdef IBM_L40 |
| outb(0x0, 0x92); |
| #else /* IBM_L40 */ |
| empty_8042(); |
| outb(KC_CMD_WOUT, K_CMD); |
| empty_8042(); |
| outb(KB_UNSET_A20, K_RDWR); |
| empty_8042(); |
| #endif /* IBM_L40 */ |
| } |
| #endif |
| |
| #ifdef ETHERBOOT32 |
| /* Serial console is only implemented in ETHERBOOT32 for now */ |
| void |
| putchar(int c) |
| { |
| #ifndef ANSIESC |
| if (c == '\n') |
| putchar('\r'); |
| #endif |
| |
| #ifdef CONSOLE_CRT |
| #ifdef ANSIESC |
| handleansi(c); |
| #else |
| putc(c); |
| #endif |
| #endif |
| #ifdef CONSOLE_SERIAL |
| #ifdef ANSIESC |
| if (c == '\n') |
| serial_putc('\r'); |
| #endif |
| serial_putc(c); |
| #endif |
| } |
| |
| /************************************************************************** |
| GETCHAR - Read the next character from the console WITHOUT ECHO |
| **************************************************************************/ |
| int |
| getchar(void) |
| { |
| int c = 256; |
| |
| do { |
| #ifdef CONSOLE_CRT |
| if (ischar()) |
| c = getc(); |
| #endif |
| #ifdef CONSOLE_SERIAL |
| if (serial_ischar()) |
| c = serial_getc(); |
| #endif |
| } while (c==256); |
| if (c == '\r') |
| c = '\n'; |
| return c; |
| } |
| |
| int |
| iskey(void) |
| { |
| #ifdef CONSOLE_CRT |
| if (ischar()) |
| return 1; |
| #endif |
| #ifdef CONSOLE_SERIAL |
| if (serial_ischar()) |
| return 1; |
| #endif |
| return 0; |
| } |
| #endif /* ETHERBOOT32 */ |
| #endif /* ! GRUB */ |
| |
| /* |
| * Local variables: |
| * c-basic-offset: 8 |
| * End: |
| */ |