1 /* $OpenBSD: bioscons.c,v 1.11 2016/05/27 05:37:51 beck Exp $ */
2
3 /*
4 * Copyright (c) 1997-1999 Michael Shalayeff
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 * THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/types.h>
30
31 #include <machine/biosvar.h>
32 #include <machine/pio.h>
33
34 #include <dev/cons.h>
35 #include <dev/ic/mc146818reg.h>
36 #include <dev/ic/comreg.h>
37 #include <dev/ic/ns16450reg.h>
38 #include <dev/isa/isareg.h>
39
40 #include <lib/libsa/stand.h>
41
42 #include "biosdev.h"
43
44 /* XXX cannot trust NVRAM on this. Maybe later we make a real probe. */
45 #if 0
46 #define PRESENT_MASK (NVRAM_EQUIPMENT_KBD|NVRAM_EQUIPMENT_DISPLAY)
47 #else
48 #define PRESENT_MASK 0
49 #endif
50
51 void
pc_probe(struct consdev * cn)52 pc_probe(struct consdev *cn)
53 {
54 cn->cn_pri = CN_MIDPRI;
55 cn->cn_dev = makedev(12, 0);
56 printf(" pc%d", minor(cn->cn_dev));
57
58 #if 0
59 outb(IO_RTC, NVRAM_EQUIPMENT);
60 if ((inb(IO_RTC+1) & PRESENT_MASK) == PRESENT_MASK) {
61 cn->cn_pri = CN_MIDPRI;
62 /* XXX from i386/conf.c */
63 cn->cn_dev = makedev(12, 0);
64 printf(" pc%d", minor(cn->cn_dev));
65 }
66 #endif
67 }
68
69 void
pc_init(struct consdev * cn)70 pc_init(struct consdev *cn)
71 {
72 }
73
74 int
pc_getc(dev_t dev)75 pc_getc(dev_t dev)
76 {
77 register int rv;
78
79 if (dev & 0x80) {
80 __asm volatile(DOINT(0x16) "; setnz %b0" : "=a" (rv) :
81 "0" (0x100) : "%ecx", "%edx", "cc" );
82 return (rv & 0xff);
83 }
84
85 /*
86 * Wait for a character to actually become available. Appears to
87 * be necessary on (at least) the Intel Mac Mini.
88 */
89 do {
90 __asm volatile(DOINT(0x16) "; setnz %b0" : "=a" (rv) :
91 "0" (0x100) : "%ecx", "%edx", "cc" );
92 } while ((rv & 0xff) == 0);
93
94 __asm volatile(DOINT(0x16) : "=a" (rv) : "0" (0x000) :
95 "%ecx", "%edx", "cc" );
96
97 return (rv & 0xff);
98 }
99
100 int
pc_getshifts(dev_t dev)101 pc_getshifts(dev_t dev)
102 {
103 register int rv;
104
105 __asm volatile(DOINT(0x16) : "=a" (rv) : "0" (0x200) :
106 "%ecx", "%edx", "cc" );
107
108 return (rv & 0xff);
109 }
110
111 void
pc_putc(dev_t dev,int c)112 pc_putc(dev_t dev, int c)
113 {
114 __asm volatile(DOINT(0x10) : : "a" (c | 0xe00), "b" (1) :
115 "%ecx", "%edx", "cc" );
116 }
117
118 const int comports[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
119
120 void
com_probe(struct consdev * cn)121 com_probe(struct consdev *cn)
122 {
123 register int i, n;
124
125 /* get equip. (9-11 # of coms) */
126 __asm volatile(DOINT(0x11) : "=a" (n) : : "%ecx", "%edx", "cc");
127 n >>= 9;
128 n &= 7;
129 for (i = 0; i < n; i++)
130 printf(" com%d", i);
131
132 cn->cn_pri = CN_LOWPRI;
133 /* XXX from i386/conf.c */
134 cn->cn_dev = makedev(8, 0);
135 }
136
137 int com_speed = -1;
138 int com_addr = -1;
139
140 void
com_init(struct consdev * cn)141 com_init(struct consdev *cn)
142 {
143 int port = (com_addr == -1) ? comports[minor(cn->cn_dev)] : com_addr;
144 time_t tt = getsecs() + 1;
145 u_long i = 1;
146
147 outb(port + com_ier, 0);
148 if (com_speed == -1)
149 comspeed(cn->cn_dev, 9600); /* default speed is 9600 baud */
150 outb(port + com_mcr, MCR_DTR | MCR_RTS);
151 outb(port + com_ier, 0);
152 outb(port + com_fifo, FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST |
153 FIFO_TRIGGER_1);
154 (void) inb(port + com_iir);
155
156 /* A few ms delay for the chip, using the getsecs() API */
157 while (!(i++ % 1000) && getsecs() < tt)
158 ;
159
160 /* drain the input buffer */
161 while (inb(port + com_lsr) & LSR_RXRDY)
162 (void)inb(port + com_data);
163 }
164
165 int
com_getc(dev_t dev)166 com_getc(dev_t dev)
167 {
168 int port = (com_addr == -1) ? comports[minor(dev & 0x7f)] : com_addr;
169
170 if (dev & 0x80)
171 return (inb(port + com_lsr) & LSR_RXRDY);
172
173 while ((inb(port + com_lsr) & LSR_RXRDY) == 0)
174 ;
175
176 return (inb(port + com_data) & 0xff);
177 }
178
179 /* call with sp == 0 to query the current speed */
180 int
comspeed(dev_t dev,int sp)181 comspeed(dev_t dev, int sp)
182 {
183 int port = (com_addr == -1) ? comports[minor(dev)] : com_addr;
184 int i, newsp;
185 int err;
186
187 if (sp <= 0)
188 return com_speed;
189 /* valid baud rate? */
190 if (115200 < sp || sp < 75)
191 return -1;
192
193 /*
194 * Accepted speeds:
195 * 75 150 300 600 1200 2400 4800 9600 19200 38400 76800 and
196 * 14400 28800 57600 115200
197 */
198 for (i = sp; i != 75 && i != 14400; i >>= 1)
199 if (i & 1)
200 return -1;
201
202 /* ripped screaming from dev/ic/com.c */
203 #define divrnd(n, q) (((n)*2/(q)+1)/2) /* divide and round off */
204 newsp = divrnd((COM_FREQ / 16), sp);
205 if (newsp <= 0)
206 return -1;
207 err = divrnd((COM_FREQ / 16) * 1000, sp * newsp) - 1000;
208 if (err < 0)
209 err = -err;
210 if (err > COM_TOLERANCE)
211 return -1;
212 #undef divrnd
213
214 if (com_speed != -1 && cn_tab && cn_tab->cn_dev == dev &&
215 com_speed != sp) {
216 printf("com%d: changing speed to %d baud in 5 seconds, "
217 "change your terminal to match!\n\a",
218 minor(dev), sp);
219 sleep(5);
220 }
221
222 outb(port + com_cfcr, LCR_DLAB);
223 outb(port + com_dlbl, newsp);
224 outb(port + com_dlbh, newsp>>8);
225 outb(port + com_cfcr, LCR_8BITS);
226 if (com_speed != -1)
227 printf("\ncom%d: %d baud\n", minor(dev), sp);
228
229 newsp = com_speed;
230 com_speed = sp;
231 return newsp;
232 }
233
234 void
com_putc(dev_t dev,int c)235 com_putc(dev_t dev, int c)
236 {
237 int port = (com_addr == -1) ? comports[minor(dev)] : com_addr;
238
239 while ((inb(port + com_lsr) & LSR_TXRDY) == 0)
240 ;
241
242 outb(port + com_data, c);
243 }
244