ofw_consinit.c revision 1.19 1 /* $NetBSD: ofw_consinit.c,v 1.19 2020/07/06 09:34:17 rin Exp $ */
2
3 /*-
4 * Copyright (c) 2007 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Tim Rightnour
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: ofw_consinit.c,v 1.19 2020/07/06 09:34:17 rin Exp $");
34
35 #include "adb.h"
36 #include "adbkbd.h"
37 #include "akbd.h"
38 #include "isa.h"
39 #include "ofb.h"
40 #include "pckbc.h"
41 #include "ukbd.h"
42 #include "wsdisplay.h"
43 #include "zsc.h"
44 #include "zstty.h"
45
46 #include <sys/param.h>
47 #include <sys/buf.h>
48 #include <sys/tty.h>
49
50 #include <prop/proplib.h>
51
52 #include <machine/autoconf.h>
53 #include <machine/trap.h>
54 #include <sys/bus.h>
55
56 #include <powerpc/ofw_cons.h>
57
58 #include <dev/cons.h>
59 #include <dev/ofw/openfirm.h>
60
61 #include <dev/wscons/wsksymvar.h>
62 #include <dev/wscons/wscons_callbacks.h>
63
64 #if NZSC > 0
65 #include <machine/z8530var.h>
66 #endif
67
68 #if (NADB > 0)
69 #include <macppc/dev/adbvar.h>
70 #endif
71
72 #if (NUKBD > 0)
73 #include <dev/usb/ukbdvar.h>
74 struct usb_kbd_ihandles {
75 struct usb_kbd_ihandles *next;
76 int ihandle;
77 };
78 #endif
79
80 #if (NZSTTY > 0)
81 #include <dev/ic/z8530reg.h>
82 extern struct consdev consdev_zs;
83 #endif
84
85 #if (NPCKBC > 0)
86 #include <dev/isa/isareg.h>
87 #include <dev/ic/i8042reg.h>
88 #include <dev/ic/pckbcvar.h>
89 #endif
90
91 int console_node = 0, console_instance = 0;
92
93 int chosen, stdin, stdout;
94 int ofkbd_ihandle;
95
96 static void cninit_kd(void);
97 static void ofwoea_bootstrap_console(void);
98 static int ofwbootcons_cngetc(dev_t);
99 static void ofwbootcons_cnputc(dev_t, int);
100
101 /*#define OFDEBUG*/
102
103 struct consdev consdev_ofwbootcons = {
104 NULL, NULL,
105 ofwbootcons_cngetc,
106 ofwbootcons_cnputc,
107 nullcnpollc,
108 NULL, NULL, NULL, NODEV, CN_INTERNAL,
109 };
110
111 #ifdef OFDEBUG
112 void ofprint(const char *, ...);
113
114 void ofprint(const char *blah, ...)
115 {
116 va_list va;
117 char buf[256];
118 int len;
119
120 va_start(va, blah);
121 len = vsnprintf(buf, sizeof(buf), blah, va);
122 va_end(va);
123 OF_write(console_instance, buf, len);
124 }
125
126 #define OFPRINTF ofprint
127 #else
128 #define OFPRINTF while(0) printf
129 #endif
130
131 void
132 cninit(void)
133 {
134 char name[32];
135
136 ofwoea_bootstrap_console();
137
138 OFPRINTF("console node: %08x\n", console_node);
139
140 if (console_node == -1)
141 goto nocons;
142
143 memset(name, 0, sizeof(name));
144 if (OF_getprop(console_node, "device_type", name, sizeof(name)) == -1)
145 goto nocons;
146
147 OFPRINTF("console type: %s\n", name);
148
149 if (strcmp(name, "serial") == 0) {
150 struct consdev *cp;
151
152 #ifdef PMAC_G5
153 /* The MMU hasn't been initialized yet, use failsafe for now */
154 extern struct consdev failsafe_cons;
155 cp = &failsafe_cons;
156 cn_tab = cp;
157 (*cp->cn_probe)(cp);
158 (*cp->cn_init)(cp);
159 aprint_verbose("Early G5 console initialized\n");
160 return;
161 #endif /* PMAC_G5 */
162
163 #if (NZSTTY > 0) && !defined(MAMBO)
164 OF_getprop(console_node, "name", name, sizeof(name));
165 if (strcmp(name, "ch-a") == 0 || strcmp(name, "ch-b") == 0) {
166 cp = &consdev_zs;
167 (*cp->cn_probe)(cp);
168 (*cp->cn_init)(cp);
169 cn_tab = cp;
170 }
171 return;
172 #endif /* NZTTY */
173
174 /* fallback to OFW boot console */
175 cp = &consdev_ofwbootcons;
176 cn_tab = cp;
177 return;
178 }
179 else
180 cninit_kd();
181 nocons:
182 return;
183 }
184
185
186 static void
187 cninit_kd(void)
188 {
189 int kstdin, node;
190 char name[16];
191 #if (NAKBD > 0) || (NADBKBD > 0)
192 int akbd;
193 #endif
194 #if NUKBD > 0
195 struct usb_kbd_ihandles *ukbds;
196 int ukbd;
197 #endif
198
199 /*
200 * Attach the console output now (so we can see debugging messages,
201 * if any).
202 */
203 #if NWSDISPLAY > 0
204 rascons_cnattach();
205 #endif
206
207 /*
208 * We must determine which keyboard type we have.
209 */
210 if (OF_getprop(chosen, "stdin", &kstdin, sizeof(kstdin))
211 != sizeof(kstdin)) {
212 printf("WARNING: no `stdin' property in /chosen\n");
213 return;
214 }
215
216 node = OF_instance_to_package(kstdin);
217 memset(name, 0, sizeof(name));
218 OF_getprop(node, "name", name, sizeof(name));
219 if (strcmp(name, "keyboard") != 0) {
220 printf("WARNING: stdin is not a keyboard: %s\n", name);
221 return;
222 }
223
224 memset(name, 0, sizeof(name));
225 OF_getprop(OF_parent(node), "name", name, sizeof(name));
226 #if NAKBD > 0
227 if (strcmp(name, "adb") == 0) {
228 printf("console keyboard type: ADB\n");
229 akbd_cnattach();
230 goto kbd_found;
231 }
232 #endif
233 #if NADBKBD > 0
234 if (strcmp(name, "adb") == 0) {
235 printf("console keyboard type: ADB\n");
236 adbkbd_cnattach();
237 goto kbd_found;
238 }
239 #endif
240 #if NPCKBC > 0
241 if (strcmp(name, "isa") == 0) {
242 printf("console keyboard type: PC Keyboard\n");
243 pckbc_cnattach(&genppc_isa_io_space_tag, IO_KBD, KBCMDP,
244 PCKBC_KBD_SLOT, 0);
245 goto kbd_found;
246 }
247 #endif
248
249 /*
250 * It is not obviously an ADB/PC keyboard. Could be USB,
251 * or ADB on some firmware versions (e.g.: iBook G4)
252 * This is not enough, we have a few more problems:
253 *
254 * (1) The stupid Macintosh firmware uses a
255 * `psuedo-hid' (no typo) or `pseudo-hid',
256 * which apparently merges all keyboards
257 * input into a single input stream.
258 * Because of this, we can't actually
259 * determine which controller or keyboard
260 * is really the console keyboard!
261 *
262 * (2) Even if we could, the keyboard can be USB,
263 * and this requires a lot of the kernel to
264 * be running in order for it to work.
265 *
266 * (3) If the keyboard is behind isa, we don't have enough
267 * kernel setup to use it yet, so punt to the ofroutines.
268 *
269 * So, what we do is this:
270 *
271 * (1) First check for OpenFirmware implementation
272 * that will not let us distinguish between
273 * USB and ADB. In that situation, try attaching
274 * anything as we can, and hope things get better
275 * at autoconfiguration time.
276 *
277 * (2) Assume the keyboard is USB.
278 * Tell the ukbd driver that it is the console.
279 * At autoconfiguration time, it will attach the
280 * first USB keyboard instance as the console
281 * keyboard.
282 *
283 * (3) Until then, so that we have _something_, we
284 * use the OpenFirmware I/O facilities to read
285 * the keyboard.
286 */
287
288 /*
289 * stdin is /pseudo-hid/keyboard. There is no
290 * `adb-kbd-ihandle or `usb-kbd-ihandles methods
291 * available. Try attaching as ADB.
292 * But only if ADB support is actually present.
293 *
294 * XXX This must be called before pmap_bootstrap().
295 */
296 if (strcmp(name, "pseudo-hid") == 0) {
297 int adb_node;
298
299 adb_node = OF_finddevice("/pci/mac-io/via-pmu/adb");
300 if (adb_node > 0) {
301 printf("ADB support found\n");
302 #if NAKBD > 0
303 akbd_cnattach();
304 #endif
305 #if NADBKBD > 0
306 adbkbd_cnattach();
307 #endif
308 } else {
309 /* must be USB */
310 printf("No ADB support present, assuming USB "
311 "keyboard\n");
312 #if NUKBD > 0
313 ukbd_cnattach();
314 #endif
315 }
316 goto kbd_found;
317 }
318
319 /*
320 * stdin is /psuedo-hid/keyboard. Test `adb-kbd-ihandle and
321 * `usb-kbd-ihandles to figure out the real keyboard(s).
322 *
323 * XXX This must be called before pmap_bootstrap().
324 */
325
326 #if NUKBD > 0
327 if (OF_call_method("`usb-kbd-ihandles", stdin, 0, 1, &ukbds) >= 0 &&
328 ukbds != NULL && ukbds->ihandle != 0 &&
329 OF_instance_to_package(ukbds->ihandle) != -1) {
330 printf("usb-kbd-ihandles matches\n");
331 printf("console keyboard type: USB\n");
332 ukbd_cnattach();
333 goto kbd_found;
334 }
335 /* Try old method name. */
336 if (OF_call_method("`usb-kbd-ihandle", kstdin, 0, 1, &ukbd) >= 0 &&
337 ukbd != 0 &&
338 OF_instance_to_package(ukbd) != -1) {
339 printf("usb-kbd-ihandle matches\n");
340 printf("console keyboard type: USB\n");
341 kstdin = ukbd;
342 ukbd_cnattach();
343 goto kbd_found;
344 }
345 #endif
346
347 #if (NAKBD > 0) || (NADBKBD > 0)
348 if (OF_call_method("`adb-kbd-ihandle", kstdin, 0, 1, &akbd) >= 0 &&
349 akbd != 0 &&
350 OF_instance_to_package(akbd) != -1) {
351 printf("adb-kbd-ihandle matches\n");
352 printf("console keyboard type: ADB\n");
353 kstdin = akbd;
354 #if NAKBD > 0
355 akbd_cnattach();
356 #endif
357 #if NADBKBD > 0
358 adbkbd_cnattach();
359 #endif
360 goto kbd_found;
361 }
362 #endif
363
364 #if NUKBD > 0
365 /*
366 * XXX Old firmware does not have `usb-kbd-ihandles method. Assume
367 * XXX USB keyboard anyway.
368 */
369 printf("defaulting to USB...");
370 printf("console keyboard type: USB\n");
371 ukbd_cnattach();
372 goto kbd_found;
373 #endif
374
375 /*
376 * No keyboard is found. Just return.
377 */
378 printf("no console keyboard\n");
379 return;
380
381 kbd_found:;
382 #if NAKBD + NUKBD + NADBKBD + NPCKBC > 0
383 /*
384 * XXX This is a little gross, but we don't get to call
385 * XXX wskbd_cnattach() twice.
386 */
387 ofkbd_ihandle = kstdin;
388 #if NWSDISPLAY > 0
389 wsdisplay_set_cons_kbd(ofkbd_cngetc, NULL, NULL);
390 #endif
391 #endif
392 }
393
394 /*
395 * Bootstrap console keyboard routines, using OpenFirmware I/O.
396 */
397 int
398 ofkbd_cngetc(dev_t dev)
399 {
400 u_char c = '\0';
401 int len;
402
403 do {
404 len = OF_read(ofkbd_ihandle, &c, 1);
405 } while (len != 1);
406
407 return c;
408 }
409
410 /*
411 * Bootstrap console support functions
412 */
413
414 static int
415 ofwbootcons_cngetc(dev_t dev)
416 {
417 unsigned char ch = '\0';
418 int l;
419
420 while ((l = OF_read(stdin, &ch, 1)) != 1)
421 if (l != -2 && l != 0)
422 return -1;
423 return ch;
424 }
425
426 static void
427 ofwbootcons_cnputc(dev_t dev, int c)
428 {
429 char ch = c;
430
431 OF_write(stdout, &ch, 1);
432 }
433
434 void
435 ofwoea_consinit(void)
436 {
437 static int initted = 0;
438
439 if (initted)
440 return;
441
442 initted = 1;
443 cninit();
444 }
445
446 static void
447 ofwoea_bootstrap_console(void)
448 {
449 int node;
450
451 chosen = OF_finddevice("/chosen");
452 if (chosen == -1)
453 goto nocons;
454
455 if (OF_getprop(chosen, "stdout", &stdout,
456 sizeof(stdout)) != sizeof(stdout))
457 goto nocons;
458 if (OF_getprop(chosen, "stdin", &stdin,
459 sizeof(stdin)) != sizeof(stdin))
460 goto nocons;
461 if (stdout == 0) {
462 /* screen should be console, but it is not open */
463 stdout = OF_open("screen");
464 }
465 node = OF_instance_to_package(stdout);
466 console_node = node;
467 console_instance = stdout;
468
469 return;
470 nocons:
471 panic("No /chosen could be found!\n");
472 console_node = -1;
473 return;
474 }
475