1/*
2 *  linux/arch/parisc/kernel/pdc_console.c
3 *
4 *  The PDC console is a simple console, which can be used for debugging
5 *  boot related problems on HP PA-RISC machines.
6 *
7 *  This code uses the ROM (=PDC) based functions to read and write characters
8 *  from and to PDC's boot path.
9 *  Since all character read from that path must be polled, this code never
10 *  can or will be a fully functional linux console.
11 */
12
13/* Define EARLY_BOOTUP_DEBUG to debug kernel related boot problems.
14 * On production kernels EARLY_BOOTUP_DEBUG should be undefined. */
15#undef EARLY_BOOTUP_DEBUG
16
17
18#include <linux/config.h>
19#include <linux/kernel.h>
20#include <linux/console.h>
21#include <linux/string.h>
22#include <linux/init.h>
23#include <linux/delay.h>
24#include <linux/sched.h>
25#include <linux/interrupt.h>
26#include <asm/page.h>
27#include <asm/types.h>
28#include <asm/system.h>
29#include <asm/pdc.h>		/* for iodc_call() proto and friends */
30
31
32static void pdc_console_write(struct console *co, const char *s, unsigned count)
33{
34	while(count--)
35		pdc_iodc_putc(*s++);
36}
37
38void pdc_outc(unsigned char c)
39{
40	pdc_iodc_outc(c);
41}
42
43
44int pdc_console_poll_key(struct console *co)
45{
46	return pdc_iodc_getc();
47}
48
49static int pdc_console_setup(struct console *co, char *options)
50{
51	return 0;
52}
53
54#ifdef CONFIG_PDC_CONSOLE
55static kdev_t pdc_console_device (struct console *c)
56{
57        return MKDEV(PDCCONS_MAJOR, 0);
58}
59#endif
60
61#ifdef CONFIG_PDC_CONSOLE
62#define PDC_CONSOLE_DEVICE pdc_console_device
63#else
64#define PDC_CONSOLE_DEVICE NULL
65#endif
66
67static struct console pdc_cons = {
68	name:		"ttyB",
69	write:		pdc_console_write,
70 	device:		PDC_CONSOLE_DEVICE,
71	setup:		pdc_console_setup,
72	flags:		CON_BOOT|CON_PRINTBUFFER|CON_ENABLED,
73	index:		-1,
74};
75
76static int pdc_console_initialized;
77
78extern unsigned long con_start;	/* kernel/printk.c */
79extern unsigned long log_end;	/* kernel/printk.c */
80
81static void pdc_console_init_force(void)
82{
83	if (pdc_console_initialized)
84		return;
85	++pdc_console_initialized;
86
87	/* If the console is duplex then copy the COUT parameters to CIN. */
88	if (PAGE0->mem_cons.cl_class == CL_DUPLEX)
89		memcpy(&PAGE0->mem_kbd, &PAGE0->mem_cons, sizeof(PAGE0->mem_cons));
90
91	/* register the pdc console */
92	register_console(&pdc_cons);
93}
94
95void pdc_console_init(void)
96{
97#if defined(EARLY_BOOTUP_DEBUG) || defined(CONFIG_PDC_CONSOLE)
98	pdc_console_init_force();
99#endif
100#ifdef EARLY_BOOTUP_DEBUG
101	printk(KERN_INFO "Initialized PDC Console for debugging.\n");
102#endif
103}
104
105
106/* Unregister the pdc console with the printk console layer */
107void pdc_console_die(void)
108{
109	if (!pdc_console_initialized)
110		return;
111	--pdc_console_initialized;
112
113	printk(KERN_INFO "Switching from PDC console\n");
114
115	/* Don't repeat what we've already printed */
116	con_start = log_end;
117
118	unregister_console(&pdc_cons);
119}
120
121
122/*
123 * Used for emergencies. Currently only used if an HPMC occurs. If an
124 * HPMC occurs, it is possible that the current console may not be
125 * properly initialed after the PDC IO reset. This routine unregisters all
126 * of the current consoles, reinitializes the pdc console and
127 * registers it.
128 */
129
130void pdc_console_restart(void)
131{
132	struct console *console;
133
134	if (pdc_console_initialized)
135		return;
136
137	while ((console = console_drivers) != NULL)
138		unregister_console(console_drivers);
139
140	/* Don't repeat what we've already printed */
141	con_start = log_end;
142
143	/* force registering the pdc console */
144	pdc_console_init_force();
145}
146
147