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