1*682a15afSmacallan /* $NetBSD: ofw_consinit.c,v 1.27 2022/12/06 01:14:36 macallan Exp $ */
2d974db0aSgarbled
3d974db0aSgarbled /*-
4d974db0aSgarbled * Copyright (c) 2007 The NetBSD Foundation, Inc.
5d974db0aSgarbled * All rights reserved.
6d974db0aSgarbled *
7d974db0aSgarbled * This code is derived from software contributed to The NetBSD Foundation
8d974db0aSgarbled * by Tim Rightnour
9d974db0aSgarbled *
10d974db0aSgarbled * Redistribution and use in source and binary forms, with or without
11d974db0aSgarbled * modification, are permitted provided that the following conditions
12d974db0aSgarbled * are met:
13d974db0aSgarbled * 1. Redistributions of source code must retain the above copyright
14d974db0aSgarbled * notice, this list of conditions and the following disclaimer.
15d974db0aSgarbled * 2. Redistributions in binary form must reproduce the above copyright
16d974db0aSgarbled * notice, this list of conditions and the following disclaimer in the
17d974db0aSgarbled * documentation and/or other materials provided with the distribution.
18d974db0aSgarbled *
19d974db0aSgarbled * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20d974db0aSgarbled * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21d974db0aSgarbled * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22d974db0aSgarbled * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23d974db0aSgarbled * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24d974db0aSgarbled * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25d974db0aSgarbled * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26d974db0aSgarbled * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27d974db0aSgarbled * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28d974db0aSgarbled * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29d974db0aSgarbled * POSSIBILITY OF SUCH DAMAGE.
30d974db0aSgarbled */
31d974db0aSgarbled
32d974db0aSgarbled #include <sys/cdefs.h>
33*682a15afSmacallan __KERNEL_RCSID(0, "$NetBSD: ofw_consinit.c,v 1.27 2022/12/06 01:14:36 macallan Exp $");
3416031f7dSrin
3516031f7dSrin #include "adb.h"
3616031f7dSrin #include "adbkbd.h"
3716031f7dSrin #include "akbd.h"
3816031f7dSrin #include "isa.h"
3916031f7dSrin #include "ofb.h"
4016031f7dSrin #include "pckbc.h"
4116031f7dSrin #include "ukbd.h"
4216031f7dSrin #include "wsdisplay.h"
4316031f7dSrin #include "zsc.h"
4416031f7dSrin #include "zstty.h"
45d974db0aSgarbled
46d974db0aSgarbled #include <sys/param.h>
47d974db0aSgarbled #include <sys/buf.h>
48d974db0aSgarbled #include <sys/tty.h>
49d974db0aSgarbled
50401165c0Suebayasi #include <prop/proplib.h>
51401165c0Suebayasi
52d974db0aSgarbled #include <machine/autoconf.h>
53d974db0aSgarbled #include <machine/trap.h>
54cf10107dSdyoung #include <sys/bus.h>
55d974db0aSgarbled
56d974db0aSgarbled #include <powerpc/ofw_cons.h>
57d309460eSthorpej #include <powerpc/ofw_machdep.h>
58d974db0aSgarbled
59d974db0aSgarbled #include <dev/cons.h>
60d974db0aSgarbled #include <dev/ofw/openfirm.h>
61d974db0aSgarbled
62d974db0aSgarbled #include <dev/wscons/wsksymvar.h>
63d974db0aSgarbled #include <dev/wscons/wscons_callbacks.h>
64d974db0aSgarbled
65d974db0aSgarbled #if NZSC > 0
66d974db0aSgarbled #include <machine/z8530var.h>
67d974db0aSgarbled #endif
68d974db0aSgarbled
69d974db0aSgarbled #if (NADB > 0)
70d974db0aSgarbled #include <macppc/dev/adbvar.h>
71d974db0aSgarbled #endif
72d974db0aSgarbled
73d974db0aSgarbled #if (NUKBD > 0)
74d974db0aSgarbled #include <dev/usb/ukbdvar.h>
75d974db0aSgarbled struct usb_kbd_ihandles {
76d974db0aSgarbled struct usb_kbd_ihandles *next;
77d974db0aSgarbled int ihandle;
78d974db0aSgarbled };
79d974db0aSgarbled #endif
80d974db0aSgarbled
81d974db0aSgarbled #if (NZSTTY > 0)
82d974db0aSgarbled #include <dev/ic/z8530reg.h>
83d974db0aSgarbled extern struct consdev consdev_zs;
84d974db0aSgarbled #endif
85d974db0aSgarbled
86d974db0aSgarbled #if (NPCKBC > 0)
87d974db0aSgarbled #include <dev/isa/isareg.h>
88d974db0aSgarbled #include <dev/ic/i8042reg.h>
89d974db0aSgarbled #include <dev/ic/pckbcvar.h>
90d974db0aSgarbled #endif
91d974db0aSgarbled
92eaaa0536Smacallan extern int console_node;
93d974db0aSgarbled
945015c904Sthorpej int ofkbd_ihandle = -1;
95d974db0aSgarbled
965015c904Sthorpej static void ofwoea_cnprobe_keyboard(void);
97d974db0aSgarbled
98d974db0aSgarbled /*#define OFDEBUG*/
99d974db0aSgarbled
100d974db0aSgarbled #ifdef OFDEBUG
101d974db0aSgarbled
102d974db0aSgarbled #define OFPRINTF ofprint
103d974db0aSgarbled #else
104d974db0aSgarbled #define OFPRINTF while(0) printf
105d974db0aSgarbled #endif
106d974db0aSgarbled
1078cefc407Smartin bool ofwoea_use_serial_console;
1085015c904Sthorpej static struct consdev *selected_serial_consdev;
1095015c904Sthorpej
1105015c904Sthorpej static int (*selected_keyboard)(void);
1115015c904Sthorpej
1125015c904Sthorpej /* XXX Gross. */
1135015c904Sthorpej #if NPCKBC > 0
1145015c904Sthorpej static int
ofwoea_pckbd_cnattach(void)1155015c904Sthorpej ofwoea_pckbd_cnattach(void)
1165015c904Sthorpej {
1175015c904Sthorpej return pckbc_cnattach(&genppc_isa_io_space_tag, IO_KBD, KBCMDP,
1185015c904Sthorpej PCKBC_KBD_SLOT, 0);
1195015c904Sthorpej }
1205015c904Sthorpej #endif
1215015c904Sthorpej
122d974db0aSgarbled void
ofwoea_cnprobe(void)1235015c904Sthorpej ofwoea_cnprobe(void)
124d974db0aSgarbled {
125b0f4d9f9Sgarbled char name[32];
126d974db0aSgarbled
127d974db0aSgarbled OFPRINTF("console node: %08x\n", console_node);
128d974db0aSgarbled
129f2afd4fbSthorpej if (console_node == -1)
1305015c904Sthorpej return;
131d974db0aSgarbled
132b0f4d9f9Sgarbled memset(name, 0, sizeof(name));
133b0f4d9f9Sgarbled if (OF_getprop(console_node, "device_type", name, sizeof(name)) == -1)
1345015c904Sthorpej return;
135d974db0aSgarbled
136b0f4d9f9Sgarbled OFPRINTF("console type: %s\n", name);
137d974db0aSgarbled
138b0f4d9f9Sgarbled if (strcmp(name, "serial") == 0) {
1398cefc407Smartin ofwoea_use_serial_console = true;
14051861415Sgarbled #ifdef PMAC_G5
141d974db0aSgarbled /* The MMU hasn't been initialized yet, use failsafe for now */
1425a4166a0Schs extern struct consdev failsafe_cons;
1435015c904Sthorpej selected_serial_consdev = &failsafe_cons;
1448cefc407Smartin aprint_verbose("Early G5 console selected "
1458cefc407Smartin "(keeping OF console for now)\n");
14651861415Sgarbled return;
14751861415Sgarbled #endif /* PMAC_G5 */
14851861415Sgarbled
14951861415Sgarbled #if (NZSTTY > 0) && !defined(MAMBO)
150d974db0aSgarbled OF_getprop(console_node, "name", name, sizeof(name));
151d974db0aSgarbled if (strcmp(name, "ch-a") == 0 || strcmp(name, "ch-b") == 0) {
1525015c904Sthorpej selected_serial_consdev = &consdev_zs;
153d974db0aSgarbled }
154d974db0aSgarbled return;
155d974db0aSgarbled #endif /* NZTTY */
156d974db0aSgarbled
157d309460eSthorpej /* fallback to OFW boot console (already set) */
158d974db0aSgarbled return;
159d974db0aSgarbled }
1605015c904Sthorpej
1615015c904Sthorpej /*
1625015c904Sthorpej * We're going to use a display console. Probe for the keyboard
1635015c904Sthorpej * we'll use.
1645015c904Sthorpej */
1655015c904Sthorpej ofwoea_cnprobe_keyboard();
166d974db0aSgarbled }
167d974db0aSgarbled
1685015c904Sthorpej /*
1695015c904Sthorpej * XXX This routine is a complete disaster, filled with platform-specific
1705015c904Sthorpej * XXX stuff. Fix, plz.
1715015c904Sthorpej */
172d974db0aSgarbled static void
ofwoea_cnprobe_keyboard(void)1735015c904Sthorpej ofwoea_cnprobe_keyboard(void)
174d974db0aSgarbled {
1755015c904Sthorpej extern int ofw_stdin;
1765015c904Sthorpej
1775015c904Sthorpej int node, kstdin = ofw_stdin;
178d974db0aSgarbled char name[16];
179d974db0aSgarbled #if (NAKBD > 0) || (NADBKBD > 0)
180d974db0aSgarbled int akbd;
181d974db0aSgarbled #endif
182d974db0aSgarbled #if NUKBD > 0
183d974db0aSgarbled struct usb_kbd_ihandles *ukbds;
184d974db0aSgarbled int ukbd;
185d974db0aSgarbled #endif
186d974db0aSgarbled
187d974db0aSgarbled /*
188d974db0aSgarbled * We must determine which keyboard type we have.
189d974db0aSgarbled */
19051861415Sgarbled node = OF_instance_to_package(kstdin);
191d974db0aSgarbled memset(name, 0, sizeof(name));
192d974db0aSgarbled OF_getprop(node, "name", name, sizeof(name));
193d974db0aSgarbled if (strcmp(name, "keyboard") != 0) {
194*682a15afSmacallan ofprint("WARNING: stdin is not a keyboard: %s\n", name);
195d974db0aSgarbled return;
196d974db0aSgarbled }
197d974db0aSgarbled
198d974db0aSgarbled memset(name, 0, sizeof(name));
199d974db0aSgarbled OF_getprop(OF_parent(node), "name", name, sizeof(name));
200b795d898Skiyohara #if NAKBD > 0
201d974db0aSgarbled if (strcmp(name, "adb") == 0) {
202*682a15afSmacallan ofprint("console keyboard type: ADB\n");
2035015c904Sthorpej selected_keyboard = akbd_cnattach;
204d974db0aSgarbled goto kbd_found;
205d974db0aSgarbled }
206d974db0aSgarbled #endif
207d974db0aSgarbled #if NADBKBD > 0
208d974db0aSgarbled if (strcmp(name, "adb") == 0) {
209*682a15afSmacallan ofprint("console keyboard type: ADB\n");
2105015c904Sthorpej selected_keyboard = adbkbd_cnattach;
211d974db0aSgarbled goto kbd_found;
212d974db0aSgarbled }
213d974db0aSgarbled #endif
214d974db0aSgarbled #if NPCKBC > 0
215b795d898Skiyohara if (strcmp(name, "isa") == 0) {
216*682a15afSmacallan ofprint("console keyboard type: PC Keyboard\n");
2175015c904Sthorpej selected_keyboard = ofwoea_pckbd_cnattach;
218d974db0aSgarbled goto kbd_found;
219d974db0aSgarbled }
220d974db0aSgarbled #endif
221d974db0aSgarbled
222d974db0aSgarbled /*
223d974db0aSgarbled * It is not obviously an ADB/PC keyboard. Could be USB,
224d974db0aSgarbled * or ADB on some firmware versions (e.g.: iBook G4)
225d974db0aSgarbled * This is not enough, we have a few more problems:
226d974db0aSgarbled *
227d974db0aSgarbled * (1) The stupid Macintosh firmware uses a
228d974db0aSgarbled * `psuedo-hid' (no typo) or `pseudo-hid',
229d974db0aSgarbled * which apparently merges all keyboards
230d974db0aSgarbled * input into a single input stream.
231d974db0aSgarbled * Because of this, we can't actually
232d974db0aSgarbled * determine which controller or keyboard
233d974db0aSgarbled * is really the console keyboard!
234d974db0aSgarbled *
235d974db0aSgarbled * (2) Even if we could, the keyboard can be USB,
236d974db0aSgarbled * and this requires a lot of the kernel to
237d974db0aSgarbled * be running in order for it to work.
238d974db0aSgarbled *
239d974db0aSgarbled * (3) If the keyboard is behind isa, we don't have enough
240d974db0aSgarbled * kernel setup to use it yet, so punt to the ofroutines.
241d974db0aSgarbled *
242d974db0aSgarbled * So, what we do is this:
243d974db0aSgarbled *
244d974db0aSgarbled * (1) First check for OpenFirmware implementation
245d974db0aSgarbled * that will not let us distinguish between
246d974db0aSgarbled * USB and ADB. In that situation, try attaching
247d974db0aSgarbled * anything as we can, and hope things get better
248d974db0aSgarbled * at autoconfiguration time.
249d974db0aSgarbled *
250d974db0aSgarbled * (2) Assume the keyboard is USB.
251d974db0aSgarbled * Tell the ukbd driver that it is the console.
252d974db0aSgarbled * At autoconfiguration time, it will attach the
253d974db0aSgarbled * first USB keyboard instance as the console
254d974db0aSgarbled * keyboard.
255d974db0aSgarbled *
256d974db0aSgarbled * (3) Until then, so that we have _something_, we
257d974db0aSgarbled * use the OpenFirmware I/O facilities to read
258d974db0aSgarbled * the keyboard.
259d974db0aSgarbled */
260d974db0aSgarbled
261d974db0aSgarbled /*
262d974db0aSgarbled * stdin is /pseudo-hid/keyboard. There is no
263d974db0aSgarbled * `adb-kbd-ihandle or `usb-kbd-ihandles methods
264d974db0aSgarbled * available. Try attaching as ADB.
26545e9b5a6Smacallan * But only if ADB support is actually present.
266d974db0aSgarbled *
267d974db0aSgarbled * XXX This must be called before pmap_bootstrap().
268d974db0aSgarbled */
269d974db0aSgarbled if (strcmp(name, "pseudo-hid") == 0) {
27045e9b5a6Smacallan int adb_node;
27145e9b5a6Smacallan
27245e9b5a6Smacallan adb_node = OF_finddevice("/pci/mac-io/via-pmu/adb");
27345e9b5a6Smacallan if (adb_node > 0) {
274*682a15afSmacallan ofprint("ADB support found\n");
275d974db0aSgarbled #if NAKBD > 0
2765015c904Sthorpej selected_keyboard = akbd_cnattach;
277d974db0aSgarbled #endif
278d974db0aSgarbled #if NADBKBD > 0
2795015c904Sthorpej selected_keyboard = adbkbd_cnattach;
280d974db0aSgarbled #endif
28145e9b5a6Smacallan } else {
28245e9b5a6Smacallan /* must be USB */
283*682a15afSmacallan ofprint("No ADB support present, assuming USB "
28445e9b5a6Smacallan "keyboard\n");
28545e9b5a6Smacallan #if NUKBD > 0
2865015c904Sthorpej selected_keyboard = ukbd_cnattach;
28745e9b5a6Smacallan #endif
28845e9b5a6Smacallan }
289d974db0aSgarbled goto kbd_found;
290d974db0aSgarbled }
291d974db0aSgarbled
292d974db0aSgarbled /*
293d974db0aSgarbled * stdin is /psuedo-hid/keyboard. Test `adb-kbd-ihandle and
294d974db0aSgarbled * `usb-kbd-ihandles to figure out the real keyboard(s).
295d974db0aSgarbled *
296d974db0aSgarbled * XXX This must be called before pmap_bootstrap().
297d974db0aSgarbled */
298d974db0aSgarbled
299d974db0aSgarbled #if NUKBD > 0
300d309460eSthorpej if (OF_call_method("`usb-kbd-ihandles", kstdin, 0, 1, &ukbds) >= 0 &&
301d974db0aSgarbled ukbds != NULL && ukbds->ihandle != 0 &&
302d974db0aSgarbled OF_instance_to_package(ukbds->ihandle) != -1) {
303*682a15afSmacallan ofprint("usb-kbd-ihandles matches\n");
304*682a15afSmacallan ofprint("console keyboard type: USB\n");
3055015c904Sthorpej selected_keyboard = ukbd_cnattach;
306d974db0aSgarbled goto kbd_found;
307d974db0aSgarbled }
308d974db0aSgarbled /* Try old method name. */
30951861415Sgarbled if (OF_call_method("`usb-kbd-ihandle", kstdin, 0, 1, &ukbd) >= 0 &&
310d974db0aSgarbled ukbd != 0 &&
311d974db0aSgarbled OF_instance_to_package(ukbd) != -1) {
312*682a15afSmacallan ofprint("usb-kbd-ihandle matches\n");
313*682a15afSmacallan ofprint("console keyboard type: USB\n");
31451861415Sgarbled kstdin = ukbd;
3155015c904Sthorpej selected_keyboard = ukbd_cnattach;
316d974db0aSgarbled goto kbd_found;
317d974db0aSgarbled }
318d974db0aSgarbled #endif
319d974db0aSgarbled
320d974db0aSgarbled #if (NAKBD > 0) || (NADBKBD > 0)
32151861415Sgarbled if (OF_call_method("`adb-kbd-ihandle", kstdin, 0, 1, &akbd) >= 0 &&
322d974db0aSgarbled akbd != 0 &&
323d974db0aSgarbled OF_instance_to_package(akbd) != -1) {
324*682a15afSmacallan ofprint("adb-kbd-ihandle matches\n");
325*682a15afSmacallan ofprint("console keyboard type: ADB\n");
32651861415Sgarbled kstdin = akbd;
327d974db0aSgarbled #if NAKBD > 0
3285015c904Sthorpej selected_keyboard = akbd_cnattach;
329d974db0aSgarbled #endif
330d974db0aSgarbled #if NADBKBD > 0
3315015c904Sthorpej selected_keyboard = adbkbd_cnattach;
332d974db0aSgarbled #endif
333d974db0aSgarbled goto kbd_found;
334d974db0aSgarbled }
335d974db0aSgarbled #endif
336d974db0aSgarbled
337d974db0aSgarbled #if NUKBD > 0
338d974db0aSgarbled /*
339d974db0aSgarbled * XXX Old firmware does not have `usb-kbd-ihandles method. Assume
340d974db0aSgarbled * XXX USB keyboard anyway.
341d974db0aSgarbled */
342*682a15afSmacallan ofprint("defaulting to USB...");
343*682a15afSmacallan ofprint("console keyboard type: USB\n");
3445015c904Sthorpej selected_keyboard = ukbd_cnattach;
345d974db0aSgarbled goto kbd_found;
346d974db0aSgarbled #endif
347d974db0aSgarbled
348d974db0aSgarbled /*
349d974db0aSgarbled * No keyboard is found. Just return.
350d974db0aSgarbled */
351*682a15afSmacallan ofprint("no console keyboard\n");
352d974db0aSgarbled return;
353d974db0aSgarbled
3545015c904Sthorpej kbd_found:
35551861415Sgarbled ofkbd_ihandle = kstdin;
356d974db0aSgarbled }
357d974db0aSgarbled
358d974db0aSgarbled /*
359d974db0aSgarbled * Bootstrap console keyboard routines, using OpenFirmware I/O.
360d974db0aSgarbled */
361d974db0aSgarbled int
ofkbd_cngetc(dev_t dev)362d974db0aSgarbled ofkbd_cngetc(dev_t dev)
363d974db0aSgarbled {
364d974db0aSgarbled u_char c = '\0';
365d974db0aSgarbled int len;
366d974db0aSgarbled
3675015c904Sthorpej KASSERT(ofkbd_ihandle != -1);
3685015c904Sthorpej
369d974db0aSgarbled do {
370d974db0aSgarbled len = OF_read(ofkbd_ihandle, &c, 1);
371d974db0aSgarbled } while (len != 1);
372d974db0aSgarbled
373d974db0aSgarbled return c;
374d974db0aSgarbled }
375d974db0aSgarbled
376d974db0aSgarbled void
cninit(void)3775015c904Sthorpej cninit(void)
3785015c904Sthorpej {
3798cefc407Smartin if (ofwoea_use_serial_console) {
3805015c904Sthorpej if (selected_serial_consdev != NULL) {
3815015c904Sthorpej cn_tab = selected_serial_consdev;
3825015c904Sthorpej (*cn_tab->cn_probe)(cn_tab);
3835015c904Sthorpej (*cn_tab->cn_init)(cn_tab);
3845015c904Sthorpej }
3855015c904Sthorpej return;
3865015c904Sthorpej }
3875015c904Sthorpej
3885015c904Sthorpej #if NWSDISPLAY > 0
3895015c904Sthorpej rascons_cnattach();
3905015c904Sthorpej #endif
3915015c904Sthorpej if (selected_keyboard != NULL) {
3925015c904Sthorpej (*selected_keyboard)();
3935015c904Sthorpej
3945015c904Sthorpej #if NWSDISPLAY > 0
3955015c904Sthorpej /*
3965015c904Sthorpej * XXX This is a little gross, but we don't get to call
3975015c904Sthorpej * XXX wskbd_cnattach() twice.
3985015c904Sthorpej */
3995015c904Sthorpej wsdisplay_set_cons_kbd(ofkbd_cngetc, NULL, NULL);
4005015c904Sthorpej #endif
4015015c904Sthorpej }
4025015c904Sthorpej }
4035015c904Sthorpej
4045015c904Sthorpej void
ofwoea_consinit(void)405d974db0aSgarbled ofwoea_consinit(void)
406d974db0aSgarbled {
407d974db0aSgarbled static int initted = 0;
408d974db0aSgarbled
409d974db0aSgarbled if (initted)
410d974db0aSgarbled return;
411d974db0aSgarbled
412d974db0aSgarbled initted = 1;
413d974db0aSgarbled cninit();
414d974db0aSgarbled }
415