diff options
Diffstat (limited to '')
-rw-r--r-- | c/src/lib/libbsp/powerpc/mcp750/console/polled_io.c | 1098 |
1 files changed, 1098 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/powerpc/mcp750/console/polled_io.c b/c/src/lib/libbsp/powerpc/mcp750/console/polled_io.c new file mode 100644 index 0000000000..1ba154c5c3 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/mcp750/console/polled_io.c @@ -0,0 +1,1098 @@ +/* + * arch/ppc/prepboot/console.c + * + * Copyright (C) 1998 Gabriel Paubert, paubert@iram.es + * + * This file is based on arch/ppc/boot/{kbd,vreset}.c in previous versions + * of Linux/PPC, mostly contributed by Gary Thomas and Cort Dougan. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include <sys/types.h> +#include <libcpu/byteorder.h> +#include <libcpu/page.h> +#include <libcpu/cpu.h> +#include <libcpu/mmu.h> +#include "keyboard.h" +#include <libcpu/io.h> +#include <string.h> +#include <stdarg.h> +#include <bsp/consoleIo.h> +#include <libcpu/spr.h> + +typedef unsigned long long u64; +typedef long long s64; +typedef unsigned int u32; + +unsigned short plain_map[NR_KEYS] = { + 0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, + 0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf07f, 0xf009, + 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69, + 0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf201, 0xf702, 0xfb61, 0xfb73, + 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b, + 0xf027, 0xf060, 0xf700, 0xf05c, 0xfb7a, 0xfb78, 0xfb63, 0xfb76, + 0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf700, 0xf30c, + 0xf703, 0xf020, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, + 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf208, 0xf209, 0xf307, + 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, + 0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf03c, 0xf10a, + 0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603, + 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, + 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +unsigned short shift_map[NR_KEYS] = { + 0xf200, 0xf01b, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e, + 0xf026, 0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf07f, 0xf009, + 0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, 0xfb49, + 0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf201, 0xf702, 0xfb41, 0xfb53, + 0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b, 0xfb4c, 0xf03a, + 0xf022, 0xf07e, 0xf700, 0xf07c, 0xfb5a, 0xfb58, 0xfb43, 0xfb56, + 0xfb42, 0xfb4e, 0xfb4d, 0xf03c, 0xf03e, 0xf03f, 0xf700, 0xf30c, + 0xf703, 0xf020, 0xf207, 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf10e, + 0xf10f, 0xf110, 0xf111, 0xf112, 0xf113, 0xf213, 0xf203, 0xf307, + 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, + 0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf03e, 0xf10a, + 0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603, + 0xf20b, 0xf601, 0xf602, 0xf117, 0xf600, 0xf20a, 0xf115, 0xf116, + 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +unsigned short altgr_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200, + 0xf07b, 0xf05b, 0xf05d, 0xf07d, 0xf05c, 0xf200, 0xf200, 0xf200, + 0xfb71, 0xfb77, 0xf918, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69, + 0xfb6f, 0xfb70, 0xf200, 0xf07e, 0xf201, 0xf702, 0xf914, 0xfb73, + 0xf917, 0xf919, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf200, + 0xf200, 0xf200, 0xf700, 0xf200, 0xfb7a, 0xfb78, 0xf916, 0xfb76, + 0xf915, 0xfb6e, 0xfb6d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c, + 0xf703, 0xf200, 0xf207, 0xf50c, 0xf50d, 0xf50e, 0xf50f, 0xf510, + 0xf511, 0xf512, 0xf513, 0xf514, 0xf515, 0xf208, 0xf202, 0xf911, + 0xf912, 0xf913, 0xf30b, 0xf90e, 0xf90f, 0xf910, 0xf30a, 0xf90b, + 0xf90c, 0xf90d, 0xf90a, 0xf310, 0xf206, 0xf200, 0xf07c, 0xf516, + 0xf517, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603, + 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, + 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +unsigned short ctrl_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e, + 0xf01f, 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf008, 0xf200, + 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009, + 0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf201, 0xf702, 0xf001, 0xf013, + 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200, + 0xf007, 0xf000, 0xf700, 0xf01c, 0xf01a, 0xf018, 0xf003, 0xf016, + 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf20e, 0xf07f, 0xf700, 0xf30c, + 0xf703, 0xf000, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, + 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf208, 0xf204, 0xf307, + 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, + 0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf200, 0xf10a, + 0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603, + 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, + 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +unsigned short shift_ctrl_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200, + 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009, + 0xf00f, 0xf010, 0xf200, 0xf200, 0xf201, 0xf702, 0xf001, 0xf013, + 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200, + 0xf200, 0xf200, 0xf700, 0xf200, 0xf01a, 0xf018, 0xf003, 0xf016, + 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c, + 0xf703, 0xf200, 0xf207, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf208, 0xf200, 0xf307, + 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, + 0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603, + 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, + 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +unsigned short alt_map[NR_KEYS] = { + 0xf200, 0xf81b, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836, + 0xf837, 0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf87f, 0xf809, + 0xf871, 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875, 0xf869, + 0xf86f, 0xf870, 0xf85b, 0xf85d, 0xf80d, 0xf702, 0xf861, 0xf873, + 0xf864, 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b, 0xf86c, 0xf83b, + 0xf827, 0xf860, 0xf700, 0xf85c, 0xf87a, 0xf878, 0xf863, 0xf876, + 0xf862, 0xf86e, 0xf86d, 0xf82c, 0xf82e, 0xf82f, 0xf700, 0xf30c, + 0xf703, 0xf820, 0xf207, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, + 0xf505, 0xf506, 0xf507, 0xf508, 0xf509, 0xf208, 0xf209, 0xf907, + 0xf908, 0xf909, 0xf30b, 0xf904, 0xf905, 0xf906, 0xf30a, 0xf901, + 0xf902, 0xf903, 0xf900, 0xf310, 0xf206, 0xf200, 0xf83c, 0xf50a, + 0xf50b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603, + 0xf118, 0xf210, 0xf211, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, + 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +unsigned short ctrl_alt_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815, 0xf809, + 0xf80f, 0xf810, 0xf200, 0xf200, 0xf201, 0xf702, 0xf801, 0xf813, + 0xf804, 0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, 0xf200, + 0xf200, 0xf200, 0xf700, 0xf200, 0xf81a, 0xf818, 0xf803, 0xf816, + 0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c, + 0xf703, 0xf200, 0xf207, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, + 0xf505, 0xf506, 0xf507, 0xf508, 0xf509, 0xf208, 0xf200, 0xf307, + 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, + 0xf302, 0xf303, 0xf300, 0xf20c, 0xf206, 0xf200, 0xf200, 0xf50a, + 0xf50b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603, + 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf20c, + 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +ushort *key_maps[MAX_NR_KEYMAPS] = { + plain_map, shift_map, altgr_map, 0, + ctrl_map, shift_ctrl_map, 0, 0, + alt_map, 0, 0, 0, + ctrl_alt_map, 0 +}; + +unsigned int keymap_count = 7; + +/* + * Philosophy: most people do not define more strings, but they who do + * often want quite a lot of string space. So, we statically allocate + * the default and allocate dynamically in chunks of 512 bytes. + */ + +char func_buf[] = { + '\033', '[', '[', 'A', 0, + '\033', '[', '[', 'B', 0, + '\033', '[', '[', 'C', 0, + '\033', '[', '[', 'D', 0, + '\033', '[', '[', 'E', 0, + '\033', '[', '1', '7', '~', 0, + '\033', '[', '1', '8', '~', 0, + '\033', '[', '1', '9', '~', 0, + '\033', '[', '2', '0', '~', 0, + '\033', '[', '2', '1', '~', 0, + '\033', '[', '2', '3', '~', 0, + '\033', '[', '2', '4', '~', 0, + '\033', '[', '2', '5', '~', 0, + '\033', '[', '2', '6', '~', 0, + '\033', '[', '2', '8', '~', 0, + '\033', '[', '2', '9', '~', 0, + '\033', '[', '3', '1', '~', 0, + '\033', '[', '3', '2', '~', 0, + '\033', '[', '3', '3', '~', 0, + '\033', '[', '3', '4', '~', 0, + '\033', '[', '1', '~', 0, + '\033', '[', '2', '~', 0, + '\033', '[', '3', '~', 0, + '\033', '[', '4', '~', 0, + '\033', '[', '5', '~', 0, + '\033', '[', '6', '~', 0, + '\033', '[', 'M', 0, + '\033', '[', 'P', 0, +}; + +char *funcbufptr = func_buf; +int funcbufsize = sizeof(func_buf); +int funcbufleft = 0; /* space left */ + +char *func_table[MAX_NR_FUNC] = { + func_buf + 0, + func_buf + 5, + func_buf + 10, + func_buf + 15, + func_buf + 20, + func_buf + 25, + func_buf + 31, + func_buf + 37, + func_buf + 43, + func_buf + 49, + func_buf + 55, + func_buf + 61, + func_buf + 67, + func_buf + 73, + func_buf + 79, + func_buf + 85, + func_buf + 91, + func_buf + 97, + func_buf + 103, + func_buf + 109, + func_buf + 115, + func_buf + 120, + func_buf + 125, + func_buf + 130, + func_buf + 135, + func_buf + 140, + func_buf + 145, + 0, + 0, + func_buf + 149, + 0, +}; + +struct kbdiacr { + unsigned char diacr, base, result; +}; + +struct kbdiacr accent_table[MAX_DIACR] = { + {'`', 'A', '\300'}, {'`', 'a', '\340'}, + {'\'', 'A', '\301'}, {'\'', 'a', '\341'}, + {'^', 'A', '\302'}, {'^', 'a', '\342'}, + {'~', 'A', '\303'}, {'~', 'a', '\343'}, + {'"', 'A', '\304'}, {'"', 'a', '\344'}, + {'O', 'A', '\305'}, {'o', 'a', '\345'}, + {'0', 'A', '\305'}, {'0', 'a', '\345'}, + {'A', 'A', '\305'}, {'a', 'a', '\345'}, + {'A', 'E', '\306'}, {'a', 'e', '\346'}, + {',', 'C', '\307'}, {',', 'c', '\347'}, + {'`', 'E', '\310'}, {'`', 'e', '\350'}, + {'\'', 'E', '\311'}, {'\'', 'e', '\351'}, + {'^', 'E', '\312'}, {'^', 'e', '\352'}, + {'"', 'E', '\313'}, {'"', 'e', '\353'}, + {'`', 'I', '\314'}, {'`', 'i', '\354'}, + {'\'', 'I', '\315'}, {'\'', 'i', '\355'}, + {'^', 'I', '\316'}, {'^', 'i', '\356'}, + {'"', 'I', '\317'}, {'"', 'i', '\357'}, + {'-', 'D', '\320'}, {'-', 'd', '\360'}, + {'~', 'N', '\321'}, {'~', 'n', '\361'}, + {'`', 'O', '\322'}, {'`', 'o', '\362'}, + {'\'', 'O', '\323'}, {'\'', 'o', '\363'}, + {'^', 'O', '\324'}, {'^', 'o', '\364'}, + {'~', 'O', '\325'}, {'~', 'o', '\365'}, + {'"', 'O', '\326'}, {'"', 'o', '\366'}, + {'/', 'O', '\330'}, {'/', 'o', '\370'}, + {'`', 'U', '\331'}, {'`', 'u', '\371'}, + {'\'', 'U', '\332'}, {'\'', 'u', '\372'}, + {'^', 'U', '\333'}, {'^', 'u', '\373'}, + {'"', 'U', '\334'}, {'"', 'u', '\374'}, + {'\'', 'Y', '\335'}, {'\'', 'y', '\375'}, + {'T', 'H', '\336'}, {'t', 'h', '\376'}, + {'s', 's', '\337'}, {'"', 'y', '\377'}, + {'s', 'z', '\337'}, {'i', 'j', '\377'}, +}; + +unsigned int accent_table_size = 68; + + + + +/* These #defines have been copied from drivers/char/pc_keyb.h, by + * Martin Mares (mj@ucw.cz). + */ +#define KBD_STATUS_REG 0x64 /* Status register (R) */ +#define KBD_CNTL_REG 0x64 /* Controller command register (W) */ +#define KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */ + +/* + * Keyboard Controller Commands + */ + +#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */ +#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */ +#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */ +#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */ +#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */ +#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */ +#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */ +#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */ +#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */ + +/* + * Keyboard Commands + */ + +#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ +#define KBD_CMD_DISABLE 0xF5 /* Disable scanning */ +#define KBD_CMD_RESET 0xFF /* Reset */ + +/* + * Keyboard Replies + */ + +#define KBD_REPLY_POR 0xAA /* Power on reset */ +#define KBD_REPLY_ACK 0xFA /* Command ACK */ +#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ + +/* + * Status Register Bits + */ + +#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */ +#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ +#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */ +#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */ +#define KBD_STAT_PERR 0x80 /* Parity error */ + +/* + * Controller Mode Register Bits + */ + +#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */ +#define KBD_MODE_SYS 0x04 /* The system flag (?) */ +#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */ +#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */ +#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */ +#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */ +#define KBD_MODE_RFU 0x80 + +SPR_RW(DEC) +SPR_RO(PVR) + + +/* Early messages after mm init but before console init are kept in log + * buffers. + */ +#define PAGE_LOG_CHARS (PAGE_SIZE-sizeof(int)-sizeof(u_long)-1) + +typedef struct _console_log { + struct _console_log *next; + int offset; + u_char data[PAGE_LOG_CHARS]; +} console_log; + +#ifdef STATIC_LOG_ALLOC + +#define STATIC_LOG_DATA_PAGE_NB 3 + +static u_char log_page_pool [STATIC_LOG_DATA_PAGE_NB * PAGE_SIZE]; + +#endif + +static board_memory_map mem_map = { + (__io_ptr) 0x80000000, + (__io_ptr) 0xc0000000, + (__io_ptr) 0xc0000000, + (__io_ptr) 0x80000000 +}; + +board_memory_map *ptr_mem_map = &mem_map; + + +struct _console_global_data { + console_log *log; + int vacuum_sent; + int lines; + int cols; + int orig_x; + int orig_y; + u_char shfts, ctls, alts, caps; +} console_global_data = {NULL, 0, 25, 80, 0, 24, 0, 0, 0, 0}; + +typedef struct console_io { + void (*putc) (const u_char); + int (*getc) (void); + int (*tstc) (void); +}console_io; + +extern console_io* curIo; + +unsigned long ticks_per_ms = 1000000; /* Decrementer ticks per ms (true for 601) */ + +void * memset(void *p, int c, size_t n) { + char *q =p; + for(; n>0; --n) *q++=c; + return p; +} + +void * memcpy(void *dst, const void * src, size_t n) { + u_char *d=dst; + const u_char *s=src; + while(n-- > 0) *d++=*s++; + return dst; +} + +char * strcat(char * dest, const char * src) +{ + char *tmp = dest; + + while (*dest) + dest++; + while ((*dest++ = *src++) != '\0') + ; + + return tmp; +} + +/* The decrementer is present on all processors and the RTC on the 601 + * has the annoying characteristic of jumping from 1e9 to 0, so we + * use the decrementer. + */ +void udelay(int us) { + us = us*ticks_per_ms/1000; + _write_DEC(us); + while((int)_read_DEC() >= 0); +} + +void debug_putc(const u_char c) +{ + curIo->putc(c); +} + +int debug_getc(void) +{ + return curIo->getc(); +} + +int debug_tstc(void) +{ + return curIo->tstc(); +} + + + +#define vidmem ((__io_ptr)(ptr_mem_map->isa_mem_base+0xb8000)) + +void vacuum_putc(u_char c) { + console_global_data.vacuum_sent++; +} + +int vacuum_getc(void) { + return -1; +} + +int vacuum_tstc(void) { + return 0; +} + +/* + * COM1 NS16550 support + */ + +#define rbr 0 +#define ier 1 +#define fcr 2 +#define lcr 3 +#define mcr 4 +#define lsr 5 +#define msr 6 +#define scr 7 +#define thr rbr +#define iir fcr +#define dll rbr +#define dlm ier + +#define LSR_DR 0x01 /* Data ready */ +#define LSR_OE 0x02 /* Overrun */ +#define LSR_PE 0x04 /* Parity error */ +#define LSR_FE 0x08 /* Framing error */ +#define LSR_BI 0x10 /* Break */ +#define LSR_THRE 0x20 /* Xmit holding register empty */ +#define LSR_TEMT 0x40 /* Xmitter empty */ +#define LSR_ERR 0x80 /* Error */ + +#define COM1 0x3F8 + +#ifdef STATIC_LOG_ALLOC +static int global_index = 0; + +static void *__palloc(int s) +{ + if (global_index ==( STATIC_LOG_DATA_PAGE_NB - 1) ) return (void*) 0; + return (void*) log_page_pool [PAGE_SIZE * global_index++]; +} + +static void pfree(void* p) +{ + --global_index; +} +#endif + + +void log_putc(const u_char c) { + console_log *l; + for(l=console_global_data.log; l; l=l->next) { + if (l->offset<PAGE_LOG_CHARS) break; + } + if (!l) { + l=__palloc(sizeof(console_log)); + memset(l, 0, sizeof(console_log)); + if (!console_global_data.log) + console_global_data.log = l; + else { + console_log *p; + for (p=console_global_data.log; + p->next; p=p->next); + p->next = l; + } + } + l->data[l->offset++] = c; +} + +/* This puts is non standard since it does not automatically add a newline + * at the end. So it is made private to avoid confusion in other files. + */ +static +void puts(const u_char *s) +{ + char c; + + while ( ( c = *s++ ) != '\0' ) { + debug_putc(c); + if ( c == '\n' ) + debug_putc('\r'); + } +} + + +static +void flush_log(void) { + console_log *p, *next; + if (console_global_data.vacuum_sent) { + printk("%d characters sent into oblivion before MM init!\n", + console_global_data.vacuum_sent); + } + for(p=console_global_data.log; p; p=next) { + puts(p->data); + next = p->next; + pfree(p); + } +} + +void serial_putc(const u_char c) +{ + while ((inb(COM1+lsr) & LSR_THRE) == 0) ; + outb(c, COM1+thr); +} + +int serial_getc(void) +{ + while ((inb(COM1+lsr) & LSR_DR) == 0) ; + return (inb(COM1+rbr)); +} + +int serial_tstc(void) +{ + return ((inb(COM1+lsr) & LSR_DR) != 0); +} + +static void scroll(void) +{ + int i; + + memcpy ( (u_char *)vidmem, (u_char *)vidmem + console_global_data.cols * 2, + ( console_global_data.lines - 1 ) * console_global_data.cols * 2 ); + for ( i = ( console_global_data.lines - 1 ) * console_global_data.cols * 2; + i < console_global_data.lines * console_global_data.cols * 2; + i += 2 ) + vidmem[i] = ' '; +} + +/* + * cursor() sets an offset (0-1999) into the 80x25 text area + */ +static void +cursor(int x, int y) +{ + int pos = console_global_data.cols*y + x; + outb(14, 0x3D4); + outb(pos>>8, 0x3D5); + outb(15, 0x3D4); + outb(pos, 0x3D5); +} + +void +vga_putc(const u_char c) +{ + int x,y; + + x = console_global_data.orig_x; + y = console_global_data.orig_y; + + if ( c == '\n' ) { + if ( ++y >= console_global_data.lines ) { + scroll(); + y--; + } + } else if (c == '\b') { + if (x > 0) { + x--; + } + } else if (c == '\r') { + x = 0; + } else { + vidmem [ ( x + console_global_data.cols * y ) * 2 ] = c; + if ( ++x >= console_global_data.cols ) { + x = 0; + if ( ++y >= console_global_data.lines ) { + scroll(); + y--; + } + } + } + + cursor(x, y); + + console_global_data.orig_x = x; + console_global_data.orig_y = y; +} + +/* Keyboard support */ +static int kbd_getc(void) +{ + unsigned char dt, brk, val; + unsigned code; +loop: + while((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0) ; + + dt = inb(KBD_DATA_REG); + + brk = dt & 0x80; /* brk == 1 on key release */ + dt = dt & 0x7f; /* keycode */ + + if (console_global_data.shfts) + code = shift_map[dt]; + else if (console_global_data.ctls) + code = ctrl_map[dt]; + else + code = plain_map[dt]; + + val = KVAL(code); + switch (KTYP(code) & 0x0f) { + case KT_LATIN: + if (brk) + break; + if (console_global_data.alts) + val |= 0x80; + if (val == 0x7f) /* map delete to backspace */ + val = '\b'; + return val; + + case KT_LETTER: + if (brk) + break; + if (console_global_data.caps) + val -= 'a'-'A'; + return val; + + case KT_SPEC: + if (brk) + break; + if (val == KVAL(K_CAPS)) + console_global_data.caps = !console_global_data.caps; + else if (val == KVAL(K_ENTER)) { +enter: /* Wait for key up */ + while (1) { + while((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0) ; + dt = inb(KBD_DATA_REG); + if (dt & 0x80) /* key up */ break; + } + return 10; + } + break; + + case KT_PAD: + if (brk) + break; + if (val < 10) + return val; + if (val == KVAL(K_PENTER)) + goto enter; + break; + + case KT_SHIFT: + switch (val) { + case KG_SHIFT: + case KG_SHIFTL: + case KG_SHIFTR: + console_global_data.shfts = brk ? 0 : 1; + break; + case KG_ALT: + case KG_ALTGR: + console_global_data.alts = brk ? 0 : 1; + break; + case KG_CTRL: + case KG_CTRLL: + case KG_CTRLR: + console_global_data.ctls = brk ? 0 : 1; + break; + } + break; + + case KT_LOCK: + switch (val) { + case KG_SHIFT: + case KG_SHIFTL: + case KG_SHIFTR: + if (brk) + console_global_data.shfts = !console_global_data.shfts; + break; + case KG_ALT: + case KG_ALTGR: + if (brk) + console_global_data.alts = !console_global_data.alts; + break; + case KG_CTRL: + case KG_CTRLL: + case KG_CTRLR: + if (brk) + console_global_data.ctls = !console_global_data.ctls; + break; + } + break; + } + /* if (brk) return (0); */ /* Ignore initial 'key up' codes */ + goto loop; +} + +static int kbd_get(int ms) { + int status, data; + while(1) { + status = inb(KBD_STATUS_REG); + if (status & KBD_STAT_OBF) { + data = inb(KBD_DATA_REG); + if (status & (KBD_STAT_GTO | KBD_STAT_PERR)) + return -1; + else + return data; + } + if (--ms < 0) return -1; + udelay(1000); + } +} + +static void kbd_put(u_char c, int ms, int port) { + while (inb(KBD_STATUS_REG) & KBD_STAT_IBF) { + if (--ms < 0) return; + udelay(1000); + } + outb(c, port); +} + +int kbdreset(void) +{ + int c; + + /* Flush all pending data */ + while(kbd_get(10) != -1); + + /* Send self-test */ + kbd_put(KBD_CCMD_SELF_TEST, 10, KBD_CNTL_REG); + c = kbd_get(1000); + if (c != 0x55) return 1; + + /* Enable then reset the KB */ + kbd_put(KBD_CCMD_KBD_ENABLE, 10, KBD_CNTL_REG); + + while (1) { + kbd_put(KBD_CMD_RESET, 10, KBD_DATA_REG); + c = kbd_get(1000); + if (c == KBD_REPLY_ACK) break; + if (c != KBD_REPLY_RESEND) return 2; + } + + if (kbd_get(1000) != KBD_REPLY_POR) return 3; + + /* Disable the keyboard while setting up the controller */ + kbd_put(KBD_CMD_DISABLE, 10, KBD_DATA_REG); + if (kbd_get(10)!=KBD_REPLY_ACK) return 4; + + /* Enable interrupts and keyboard controller */ + kbd_put(KBD_CCMD_WRITE_MODE, 10, KBD_CNTL_REG); + kbd_put(KBD_MODE_KBD_INT | KBD_MODE_SYS | + KBD_MODE_DISABLE_MOUSE | KBD_MODE_KCC, + 10, KBD_DATA_REG); + + /* Reenable the keyboard */ + kbd_put(KBD_CMD_ENABLE, 10, KBD_DATA_REG); + if (kbd_get(10)!=KBD_REPLY_ACK) return 5; + + return 0; +} + +int kbd_tstc(void) +{ + return ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) != 0); +} + +const struct console_io +vacuum_console_functions = { + vacuum_putc, + vacuum_getc, + vacuum_tstc +}; + +static const struct console_io +log_console_functions = { + log_putc, + vacuum_getc, + vacuum_tstc +}, + +serial_console_functions = { + serial_putc, + serial_getc, + serial_tstc +}, + +vga_console_functions = { + vga_putc, + kbd_getc, + kbd_tstc +}; + +console_io* curIo = &vacuum_console_functions; + +int select_console(ioType t) { + static ioType curType = CONSOLE_VACUUM; + + switch (t) { + case CONSOLE_VACUUM : curIo = &vacuum_console_functions; break; + case CONSOLE_LOG : curIo = &log_console_functions; break; + case CONSOLE_SERIAL : curIo = &serial_console_functions; break; + case CONSOLE_VGA : curIo = &vga_console_functions; break; + default : curIo = &vacuum_console_functions;break; + } + if (curType == CONSOLE_LOG) flush_log(); + curType = t; + return 0; +} + +/* we use this so that we can do without the ctype library */ +#define is_digit(c) ((c) >= '0' && (c) <= '9') + + +static int skip_atoi(const char **s) +{ + int i=0; + + while (is_digit(**s)) + i = i*10 + *((*s)++) - '0'; + return i; +} + +/* Based on linux/lib/vsprintf.c and modified to suit our needs, + * bloat has been limited since we basically only need %u, %x, %s and %c. + * But we need 64 bit values ! + */ + +int printk(const char *fmt, ...) { + va_list args; + int i; + /* Should not be a problem with 8kB of stack */ + char buf[1024]; + + va_start(args, fmt); + i = vsprintf(buf, fmt, args); + va_end(args); + puts(buf); + return i; +} + +/* Necessary to avoid including a library, and GCC won't do this inline. */ +#define div10(num, rmd) \ +do { u32 t1, t2, t3; \ + asm("lis %4,0xcccd; " \ + "addi %4,%4,0xffffcccd; " /* Build 0xcccccccd */ \ + "mulhwu %3,%0+1,%4; " /* (num.l*cst.l).h */ \ + "mullw %2,%0,%4; " /* (num.h*cst.l).l */ \ + "addc %3,%3,%2; " \ + "mulhwu %2,%0,%4; " /* (num.h*cst.l).h */ \ + "addi %4,%4,-1; " /* Build 0xcccccccc */ \ + "mullw %1,%0,%4; " /* (num.h*cst.h).l */ \ + "adde %2,%2,%1; " \ + "mulhwu %1,%0,%4; " /* (num.h*cst.h).h */ \ + "addze %1,%1; " \ + "mullw %0,%0+1,%4; " /* (num.l*cst.h).l */ \ + "addc %3,%3,%0; " \ + "mulhwu %0,%0+1,%4; " /* (num.l*cst.h).h */ \ + "adde %2,%2,%0; " \ + "addze %1,%1; " \ + "srwi %2,%2,3; " \ + "srwi %0,%1,3; " \ + "rlwimi %2,%1,29,0,2; " \ + "mulli %4,%2,10; " \ + "sub %4,%0+1,%4; " \ + "mr %0+1,%2; " : \ + "=r" (num), "=&r" (t1), "=&r" (t2), "=&r"(t3), "=&b" (rmd) : \ + "0" (num)); \ + \ +} while(0); + +#define SIGN 1 /* unsigned/signed long */ +#define LARGE 2 /* use 'ABCDEF' instead of 'abcdef' */ +#define HEX 4 /* hexadecimal instead of decimal */ +#define ADDR 8 /* Value is an addres (p) */ +#define ZEROPAD 16 /* pad with zero */ +#define HALF 32 +#define LONG 64 /* long argument */ +#define LLONG 128 /* 64 bit argument */ + +static char * number(char * str, int size, int type, u64 num) +{ + char fill,sign,tmp[24]; + const char *digits="0123456789abcdef"; + int i; + + if (type & LARGE) + digits = "0123456789ABCDEF"; + fill = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) { + if ((s64)num <0) { + sign = '-'; + num = -num; + size--; + } + } + + i = 0; + do { + unsigned rem; + if (type&HEX) { + rem = num & 0x0f; + num >>=4; + } else { + div10(num, rem); + } + tmp[i++] = digits[rem]; + } while (num != 0); + + size -= i; + if (!(type&(ZEROPAD))) + while(size-->0) + *str++ = ' '; + if (sign) + *str++ = sign; + + while (size-- > 0) + *str++ = fill; + while (i-- > 0) + *str++ = tmp[i]; + while (size-- > 0) + *str++ = ' '; + return str; +} + +int vsprintf(char *buf, const char *fmt, va_list args) +{ + int len; + u64 num; + int i; + char * str; + const char *s; + + int flags; /* flags to number() and private */ + + int field_width; /* width of output field */ + + for (str=buf ; *fmt ; ++fmt) { + if (*fmt != '%') { + *str++ = *fmt; + continue; + } + + /* process flags, only 0 padding needed */ + flags = 0; + if (*++fmt == '0' ) { + flags |= ZEROPAD; + fmt++; + } + + /* get field width */ + field_width = -1; + if (is_digit(*fmt)) + field_width = skip_atoi(&fmt); + + /* get the conversion qualifier */ + if (*fmt == 'h') { + flags |= HALF; + fmt++; + } else if (*fmt == 'L') { + flags |= LLONG; + fmt++; + } else if (*fmt == 'l') { + flags |= LONG; + fmt++; + } + + switch (*fmt) { + case 'c': + *str++ = (unsigned char) va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + continue; + + case 's': + s = va_arg(args, char *); + len = strlen(s); + + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + continue; + + case 'p': + if (field_width == -1) { + field_width = 2*sizeof(void *); + } + flags |= ZEROPAD|HEX|ADDR; + break; + + case 'X': + flags |= LARGE; + case 'x': + flags |= HEX; + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break; + + default: + if (*fmt != '%') + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + continue; + } + /* This ugly code tries to minimize the number of va_arg() + * since they expand to a lot of code on PPC under the SYSV + * calling conventions (but not with -mcall-aix which has + * other problems). Arguments have at least the size of a + * long allocated, and we use this fact to minimize bloat. + * (and pointers are assimilated to unsigned long too). + */ + if (sizeof(long long) > sizeof(long) && flags & LLONG) + num = va_arg(args, unsigned long long); + else { + u_long n = va_arg(args, unsigned long); + if (flags & HALF) { + if (flags & SIGN) + n = (short) n; + else + n = (unsigned short) n; + } else if (! flags & LONG) { + /* Here the compiler correctly removes this + * do nothing code on 32 bit PPC. + */ + if (flags & SIGN) + n = (int) n; + else + n = (unsigned) n; + } + if (flags & SIGN) num = (long) n; else num = n; + } + str = number(str, field_width, flags, num); + } + *str = '\0'; + return str-buf; +} |