diff options
Diffstat (limited to 'arch/parisc/kernel/pdc_cons.c')
-rw-r--r-- | arch/parisc/kernel/pdc_cons.c | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/arch/parisc/kernel/pdc_cons.c b/arch/parisc/kernel/pdc_cons.c new file mode 100644 index 000000000000..01f676d1673b --- /dev/null +++ b/arch/parisc/kernel/pdc_cons.c | |||
@@ -0,0 +1,189 @@ | |||
1 | /* | ||
2 | * PDC Console support - ie use firmware to dump text via boot console | ||
3 | * | ||
4 | * Copyright (C) 1999-2003 Matthew Wilcox <willy at parisc-linux.org> | ||
5 | * Copyright (C) 2000 Martin K Petersen <mkp at mkp.net> | ||
6 | * Copyright (C) 2000 John Marvin <jsm at parisc-linux.org> | ||
7 | * Copyright (C) 2000-2003 Paul Bame <bame at parisc-linux.org> | ||
8 | * Copyright (C) 2000 Philipp Rumpf <prumpf with tux.org> | ||
9 | * Copyright (C) 2000 Michael Ang <mang with subcarrier.org> | ||
10 | * Copyright (C) 2000 Grant Grundler <grundler with parisc-linux.org> | ||
11 | * Copyright (C) 2001-2002 Ryan Bradetich <rbrad at parisc-linux.org> | ||
12 | * Copyright (C) 2001 Helge Deller <deller at parisc-linux.org> | ||
13 | * Copyright (C) 2001 Thomas Bogendoerfer <tsbogend at parisc-linux.org> | ||
14 | * Copyright (C) 2002 Randolph Chung <tausq with parisc-linux.org> | ||
15 | * | ||
16 | * | ||
17 | * This program is free software; you can redistribute it and/or modify | ||
18 | * it under the terms of the GNU General Public License as published by | ||
19 | * the Free Software Foundation; either version 2 of the License, or | ||
20 | * (at your option) any later version. | ||
21 | * | ||
22 | * This program is distributed in the hope that it will be useful, | ||
23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
25 | * GNU General Public License for more details. | ||
26 | * | ||
27 | * You should have received a copy of the GNU General Public License | ||
28 | * along with this program; if not, write to the Free Software | ||
29 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
30 | */ | ||
31 | |||
32 | /* | ||
33 | * The PDC console is a simple console, which can be used for debugging | ||
34 | * boot related problems on HP PA-RISC machines. | ||
35 | * | ||
36 | * This code uses the ROM (=PDC) based functions to read and write characters | ||
37 | * from and to PDC's boot path. | ||
38 | * Since all character read from that path must be polled, this code never | ||
39 | * can or will be a fully functional linux console. | ||
40 | */ | ||
41 | |||
42 | /* Define EARLY_BOOTUP_DEBUG to debug kernel related boot problems. | ||
43 | * On production kernels EARLY_BOOTUP_DEBUG should be undefined. */ | ||
44 | #undef EARLY_BOOTUP_DEBUG | ||
45 | |||
46 | |||
47 | #include <linux/config.h> | ||
48 | #include <linux/kernel.h> | ||
49 | #include <linux/console.h> | ||
50 | #include <linux/string.h> | ||
51 | #include <linux/init.h> | ||
52 | #include <linux/delay.h> | ||
53 | #include <linux/sched.h> | ||
54 | #include <linux/interrupt.h> | ||
55 | #include <linux/major.h> | ||
56 | #include <linux/tty.h> | ||
57 | #include <asm/page.h> | ||
58 | #include <asm/types.h> | ||
59 | #include <asm/system.h> | ||
60 | #include <asm/pdc.h> /* for iodc_call() proto and friends */ | ||
61 | |||
62 | |||
63 | static void pdc_console_write(struct console *co, const char *s, unsigned count) | ||
64 | { | ||
65 | while(count--) | ||
66 | pdc_iodc_putc(*s++); | ||
67 | } | ||
68 | |||
69 | void pdc_outc(unsigned char c) | ||
70 | { | ||
71 | pdc_iodc_outc(c); | ||
72 | } | ||
73 | |||
74 | void pdc_printf(const char *fmt, ...) | ||
75 | { | ||
76 | va_list args; | ||
77 | char buf[1024]; | ||
78 | int i, len; | ||
79 | |||
80 | va_start(args, fmt); | ||
81 | len = vscnprintf(buf, sizeof(buf), fmt, args); | ||
82 | va_end(args); | ||
83 | |||
84 | for (i = 0; i < len; i++) | ||
85 | pdc_iodc_outc(buf[i]); | ||
86 | } | ||
87 | |||
88 | int pdc_console_poll_key(struct console *co) | ||
89 | { | ||
90 | return pdc_iodc_getc(); | ||
91 | } | ||
92 | |||
93 | static int pdc_console_setup(struct console *co, char *options) | ||
94 | { | ||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | #if defined(CONFIG_PDC_CONSOLE) | ||
99 | #define PDC_CONSOLE_DEVICE pdc_console_device | ||
100 | static struct tty_driver * pdc_console_device (struct console *c, int *index) | ||
101 | { | ||
102 | extern struct tty_driver console_driver; | ||
103 | *index = c->index ? c->index-1 : fg_console; | ||
104 | return &console_driver; | ||
105 | } | ||
106 | #else | ||
107 | #define PDC_CONSOLE_DEVICE NULL | ||
108 | #endif | ||
109 | |||
110 | static struct console pdc_cons = { | ||
111 | .name = "ttyB", | ||
112 | .write = pdc_console_write, | ||
113 | .device = PDC_CONSOLE_DEVICE, | ||
114 | .setup = pdc_console_setup, | ||
115 | .flags = CON_BOOT|CON_PRINTBUFFER|CON_ENABLED, | ||
116 | .index = -1, | ||
117 | }; | ||
118 | |||
119 | static int pdc_console_initialized; | ||
120 | extern unsigned long con_start; /* kernel/printk.c */ | ||
121 | extern unsigned long log_end; /* kernel/printk.c */ | ||
122 | |||
123 | |||
124 | static void pdc_console_init_force(void) | ||
125 | { | ||
126 | if (pdc_console_initialized) | ||
127 | return; | ||
128 | ++pdc_console_initialized; | ||
129 | |||
130 | /* If the console is duplex then copy the COUT parameters to CIN. */ | ||
131 | if (PAGE0->mem_cons.cl_class == CL_DUPLEX) | ||
132 | memcpy(&PAGE0->mem_kbd, &PAGE0->mem_cons, sizeof(PAGE0->mem_cons)); | ||
133 | |||
134 | /* register the pdc console */ | ||
135 | register_console(&pdc_cons); | ||
136 | } | ||
137 | |||
138 | void __init pdc_console_init(void) | ||
139 | { | ||
140 | #if defined(EARLY_BOOTUP_DEBUG) || defined(CONFIG_PDC_CONSOLE) | ||
141 | pdc_console_init_force(); | ||
142 | #endif | ||
143 | #ifdef EARLY_BOOTUP_DEBUG | ||
144 | printk(KERN_INFO "Initialized PDC Console for debugging.\n"); | ||
145 | #endif | ||
146 | } | ||
147 | |||
148 | |||
149 | /* Unregister the pdc console with the printk console layer */ | ||
150 | void pdc_console_die(void) | ||
151 | { | ||
152 | if (!pdc_console_initialized) | ||
153 | return; | ||
154 | --pdc_console_initialized; | ||
155 | |||
156 | printk(KERN_INFO "Switching from PDC console\n"); | ||
157 | |||
158 | /* Don't repeat what we've already printed */ | ||
159 | con_start = log_end; | ||
160 | |||
161 | unregister_console(&pdc_cons); | ||
162 | } | ||
163 | |||
164 | |||
165 | /* | ||
166 | * Used for emergencies. Currently only used if an HPMC occurs. If an | ||
167 | * HPMC occurs, it is possible that the current console may not be | ||
168 | * properly initialed after the PDC IO reset. This routine unregisters all | ||
169 | * of the current consoles, reinitializes the pdc console and | ||
170 | * registers it. | ||
171 | */ | ||
172 | |||
173 | void pdc_console_restart(void) | ||
174 | { | ||
175 | struct console *console; | ||
176 | |||
177 | if (pdc_console_initialized) | ||
178 | return; | ||
179 | |||
180 | while ((console = console_drivers) != NULL) | ||
181 | unregister_console(console_drivers); | ||
182 | |||
183 | /* Don't repeat what we've already printed */ | ||
184 | con_start = log_end; | ||
185 | |||
186 | /* force registering the pdc console */ | ||
187 | pdc_console_init_force(); | ||
188 | } | ||
189 | |||