xref: /netbsd-src/sys/arch/powerpc/oea/ofw_consinit.c (revision 682a15af405f3bcbe321cb9b11c508a1007c3d6e)
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