File: /usr/src/linux/arch/mips/mips-boards/generic/printf.c
1 /*
2 * Carsten Langgaard, carstenl@mips.com
3 * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
4 *
5 * ########################################################################
6 *
7 * This program is free software; you can distribute it and/or modify it
8 * under the terms of the GNU General Public License (Version 2) as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
19 *
20 * ########################################################################
21 *
22 * Putting things on the screen/serial line using YAMONs facilities.
23 *
24 */
25 #include <linux/config.h>
26 #include <linux/init.h>
27 #include <linux/kernel.h>
28 #include <linux/serialP.h>
29 #include <linux/serial_reg.h>
30 #include <asm/system.h>
31 #include <asm/io.h>
32 #include <asm/serial.h>
33
34
35 #ifdef CONFIG_MIPS_ATLAS
36 /*
37 * Atlas registers are memory mapped on 64-bit aligned boundaries and
38 * only word access are allowed.
39 * When reading the UART 8 bit registers only the LSB are valid.
40 */
41 unsigned int atlas_serial_in(struct async_struct *info, int offset)
42 {
43 return (*(volatile unsigned int *)(info->port + mips_io_port_base + offset*8) & 0xff);
44 }
45
46 void atlas_serial_out(struct async_struct *info, int offset, int value)
47 {
48 *(volatile unsigned int *)(info->port + mips_io_port_base + offset*8) = value;
49 }
50
51 #define serial_in atlas_serial_in
52 #define serial_out atlas_serial_out
53
54 #else
55
56 static unsigned int serial_in(struct async_struct *info, int offset)
57 {
58 return inb(info->port + offset);
59 }
60
61 static void serial_out(struct async_struct *info, int offset,
62 int value)
63 {
64 outb(value, info->port + offset);
65 }
66 #endif
67
68 static struct serial_state rs_table[] = {
69 SERIAL_PORT_DFNS /* Defined in serial.h */
70 };
71
72 /*
73 * Hooks to fake "prom" console I/O before devices
74 * are fully initialized.
75 */
76 static struct async_struct prom_port_info = {0};
77
78 void __init setup_prom_printf(int tty_no) {
79 struct serial_state *ser = &rs_table[tty_no];
80
81 prom_port_info.state = ser;
82 prom_port_info.magic = SERIAL_MAGIC;
83 prom_port_info.port = ser->port;
84 prom_port_info.flags = ser->flags;
85
86 /* No setup of UART - assume YAMON left in sane state */
87 }
88
89 int putPromChar(char c)
90 {
91 if (!prom_port_info.state) { /* need to init device first */
92 return 0;
93 }
94
95 while ((serial_in(&prom_port_info, UART_LSR) & UART_LSR_THRE) == 0)
96 ;
97
98 serial_out(&prom_port_info, UART_TX, c);
99
100 return 1;
101 }
102
103 char getPromChar(void)
104 {
105 if (!prom_port_info.state) { /* need to init device first */
106 return 0;
107 }
108
109 while (!(serial_in(&prom_port_info, UART_LSR) & 1))
110 ;
111
112 return(serial_in(&prom_port_info, UART_RX));
113 }
114
115 static char buf[1024];
116
117 void __init prom_printf(char *fmt, ...)
118 {
119 va_list args;
120 int l;
121 char *p, *buf_end;
122 long flags;
123
124 int putPromChar(char);
125
126 /* Low level, brute force, not SMP safe... */
127 save_and_cli(flags);
128 va_start(args, fmt);
129 l = vsprintf(buf, fmt, args); /* hopefully i < sizeof(buf) */
130 va_end(args);
131
132 buf_end = buf + l;
133
134 for (p = buf; p < buf_end; p++) {
135 /* Crude cr/nl handling is better than none */
136 if(*p == '\n')putPromChar('\r');
137 putPromChar(*p);
138 }
139 restore_flags(flags);
140 }
141