File: /usr/src/linux/arch/parisc/kernel/pdc_cons.c
1 #include <linux/config.h>
2 #include <linux/kernel.h>
3 #include <linux/console.h>
4 #include <linux/string.h>
5 #include <linux/init.h>
6 #include <linux/delay.h>
7 #include <linux/interrupt.h>
8 #include <asm/page.h>
9 #include <asm/types.h>
10 #include <asm/system.h>
11 #include <asm/pdc.h> /* for iodc_call() proto and friends */
12 #include <asm/real.h>
13
14 static int __attribute__((aligned(8))) iodc_retbuf[32];
15 static char __attribute__((aligned(64))) iodc_dbuf[4096];
16
17 /*
18 * pdc_putc:
19 * Console character print using IODC.
20 *
21 * Note that only these special chars are architected for console IODC io:
22 * BEL, BS, CR, and LF. Others are passed through.
23 * Since the HP console requires CR+LF to perform a 'newline', we translate
24 * "\n" to "\r\n".
25 */
26
27 static int posx; /* for simple TAB-Simulation... */
28
29 /* XXX Should we spinlock posx usage */
30
31 void pdc_putc(unsigned char c)
32 {
33 unsigned int n;
34 unsigned long flags;
35
36 switch (c) {
37 case '\n':
38 iodc_dbuf[0] = '\r';
39 iodc_dbuf[1] = '\n';
40 n = 2;
41 posx = 0;
42 break;
43 case '\t':
44 pdc_putc(' ');
45 while (posx & 7) /* expand TAB */
46 pdc_putc(' ');
47 return; /* return since IODC can't handle this */
48 case '\b':
49 posx-=2; /* BS */
50 default:
51 iodc_dbuf[0] = c;
52 n = 1;
53 posx++;
54 break;
55 }
56 {
57 real32_call(PAGE0->mem_cons.iodc_io,
58 (unsigned long)PAGE0->mem_cons.hpa, ENTRY_IO_COUT,
59 PAGE0->mem_cons.spa, __pa(PAGE0->mem_cons.dp.layers),
60 __pa(iodc_retbuf), 0, __pa(iodc_dbuf), n, 0);
61 }
62 }
63
64 static void pdc_console_write(struct console *co, const char *s, unsigned count)
65 {
66 while(count--)
67 pdc_putc(*s++);
68 }
69
70 int pdc_console_wait_key(struct console *co)
71 {
72 int ch = 'X';
73 int status;
74
75 /* Bail if no console input device. */
76 if (!PAGE0->mem_kbd.iodc_io)
77 return 0;
78
79 /* wait for a keyboard (rs232)-input */
80 do {
81 unsigned long flags;
82
83 save_flags(flags);
84 cli();
85 status = real32_call(PAGE0->mem_kbd.iodc_io,
86 (unsigned long)PAGE0->mem_kbd.hpa, ENTRY_IO_CIN,
87 PAGE0->mem_kbd.spa, __pa(PAGE0->mem_kbd.dp.layers),
88 __pa(iodc_retbuf), 0, __pa(iodc_dbuf), 1, 0);
89 restore_flags(flags);
90 ch = *iodc_dbuf; /* save the character directly to ch */
91 } while (*iodc_retbuf == 0); /* wait for a key */
92 return ch;
93 }
94
95 int pdc_getc(void)
96 {
97 return pdc_console_wait_key(NULL);
98 }
99
100 static int pdc_console_setup(struct console *co, char *options)
101 {
102 return 0;
103 }
104
105 static struct console pdc_cons = {
106 name: "ttyB",
107 write: pdc_console_write,
108 read: NULL,
109 device: NULL,
110 wait_key: pdc_console_wait_key,
111 unblank: NULL,
112 setup: pdc_console_setup,
113 flags: CON_PRINTBUFFER|CON_ENABLED, // |CON_CONSDEV,
114 index: -1,
115 };
116
117 static int pdc_console_initialized;
118
119 void pdc_console_init(void)
120 {
121 if (pdc_console_initialized)
122 return;
123 ++pdc_console_initialized;
124
125 /* If the console is duplex then copy the COUT parameters to CIN. */
126 if (PAGE0->mem_cons.cl_class == CL_DUPLEX)
127 memcpy(&PAGE0->mem_kbd, &PAGE0->mem_cons, sizeof(PAGE0->mem_cons));
128
129 pdc_console_write(0, "PDC Console Initialized\n", 24);
130 /* register the pdc console */
131 register_console(&pdc_cons);
132 }
133
134
135 /* Unregister the pdc console with the printk console layer */
136 void pdc_console_die(void)
137 {
138 printk("Switching from PDC console\n");
139 if (!pdc_console_initialized)
140 return;
141 --pdc_console_initialized;
142
143 #ifdef CONFIG_VT_CONSOLE
144 schedule_console_callback();
145 #endif
146
147 unregister_console(&pdc_cons);
148 }
149
150
151 /*
152 * Used for emergencies. Currently only used if an HPMC occurs. If an
153 * HPMC occurs, it is possible that the current console may not be
154 * properly initialed after the PDC IO reset. This routine unregisters all
155 * of the current consoles, reinitializes the pdc console and
156 * registers it.
157 */
158
159 void pdc_console_restart(void)
160 {
161 struct console *console;
162 extern int log_size;
163
164 if (pdc_console_initialized)
165 return;
166
167 while ((console = console_drivers) != (struct console *)0)
168 unregister_console(console_drivers);
169
170 log_size = 0;
171 pdc_console_init();
172 printk("Switched to PDC console\n");
173 return;
174 }
175
176