Home | History | Annotate | Line # | Download | only in rs6000
      1 /*	$NetBSD: machdep.c,v 1.16 2026/04/05 10:19:57 andvar 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: machdep.c,v 1.16 2026/04/05 10:19:57 andvar Exp $");
     34 
     35 #include "opt_compat_netbsd.h"
     36 #include "opt_ddb.h"
     37 #include "opt_modular.h"
     38 
     39 #include <sys/param.h>
     40 #include <sys/buf.h>
     41 #include <sys/bus.h>
     42 #include <sys/conf.h>
     43 #include <sys/device.h>
     44 #include <sys/exec.h>
     45 #include <sys/extent.h>
     46 #include <sys/intr.h>
     47 #include <sys/kernel.h>
     48 #include <sys/ksyms.h>
     49 #include <sys/mbuf.h>
     50 #include <sys/mount.h>
     51 #include <sys/msgbuf.h>
     52 #include <sys/proc.h>
     53 #include <sys/reboot.h>
     54 #include <sys/syscallargs.h>
     55 #include <sys/sysctl.h>
     56 #include <sys/syslog.h>
     57 #include <sys/systm.h>
     58 
     59 #include <uvm/uvm_extern.h>
     60 
     61 #include <machine/autoconf.h>
     62 #include <machine/bootinfo.h>
     63 #include <machine/powerpc.h>
     64 #include <machine/iplcb.h>
     65 
     66 #include <powerpc/pmap.h>
     67 #include <powerpc/trap.h>
     68 
     69 #include <powerpc/oea/bat.h>
     70 #include <powerpc/pio.h>
     71 #include <powerpc/pic/picvar.h>
     72 
     73 #include <dev/cons.h>
     74 
     75 #include "com.h"
     76 #if (NCOM > 0)
     77 #include <sys/termios.h>
     78 #include <dev/ic/comreg.h>
     79 #include <dev/ic/comvar.h>
     80 void comsoft(void);
     81 #endif
     82 
     83 #ifdef DDB
     84 #include <powerpc/db_machdep.h>
     85 #include <ddb/db_extern.h>
     86 #endif
     87 
     88 #include "ksyms.h"
     89 
     90 void initppc(u_long, u_long, u_int, void *);
     91 void dumpsys(void);
     92 void strayintr(int);
     93 void rs6000_bus_space_init(void);
     94 void setled(uint32_t);
     95 void say_hi(void);
     96 static void init_intr(void);
     97 
     98 char bootinfo[BOOTINFO_MAXSIZE];
     99 char bootpath[256];
    100 struct ipl_directory	*ipldir;
    101 struct ipl_cb		*iplcb;
    102 struct ipl_info		*iplinfo;
    103 int led_avail;
    104 struct sys_info		*sysinfo;
    105 struct buc_info		*bucinfo[MAX_BUCS];
    106 int nrofbucs;
    107 
    108 struct pic_ops *pic_iocc;
    109 
    110 #define	OFMEMREGIONS	32
    111 struct mem_region physmemr[OFMEMREGIONS], availmemr[OFMEMREGIONS];
    112 
    113 paddr_t avail_end;			/* XXX temporary */
    114 extern register_t iosrtable[16];
    115 
    116 #if NKSYMS || defined(DDB) || defined(MODULAR)
    117 extern void *endsym, *startsym;
    118 #endif
    119 
    120 #ifndef CONCOMADDR
    121 #define CONCOMADDR 0x30
    122 #endif
    123 
    124 #ifndef CONSPEED
    125 #define CONSPEED 9600
    126 #endif
    127 
    128 #ifndef CONMODE
    129 #define CONMODE ((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8) /* 8N1 */
    130 #endif
    131 
    132 int comcnspeed = CONSPEED;
    133 int comcnmode = CONMODE;
    134 struct consdev kcomcons;
    135 static void kcomcnputc(dev_t, int);
    136 
    137 extern struct pic_ops *setup_iocc(void);
    138 
    139 
    140 void
    141 say_hi(void)
    142 {
    143 	printf("HELLO?!\n");
    144 	setled(0x55500000);
    145 #ifdef DDB
    146 	Debugger();
    147 #endif
    148 #if 0
    149         li      %r28,0x00000041 /* PUT A to R28*/
    150         li      %r29,0x30       /* put serial addr to r29*/
    151         addis   %r29,%r29,0xc000 /* r29 now holds serial addr*/
    152         stb     %r28,0(%r29)  /* slam it to serial port*/
    153 loopforever:
    154         bla     loopforever
    155 #endif
    156 }
    157 /*
    158  * Set LED's.  Yes I know this is ugly. Yes I will rewrite it in pure asm.
    159  */
    160 void
    161 setled(uint32_t val)
    162 {
    163 #if 0
    164 	register_t savemsr, msr, savesr15;
    165 
    166 	__asm volatile ("mfmsr %0" : "=r"(savemsr));
    167 	msr = savemsr & ~PSL_DR;
    168 	__asm volatile ("mtmsr %0" : : "r"(msr));
    169 
    170 	__asm volatile ("mfsr %0,15;isync" : "=r"(savesr15));
    171 	__asm volatile ("mtsr 15,%0" : : "r"(0x82040080));
    172 	__asm volatile ("mtmsr %0" : : "r"(msr|PSL_DR));
    173 	__asm volatile ("isync");
    174 	*(uint32_t *)0xF0A00300 = val;
    175 	__asm volatile ("mtmsr %0" : : "r"(savemsr));
    176 	__asm volatile ("mtsr 15,%0;isync" : : "r"(savesr15));
    177 #endif
    178 	if (led_avail)
    179 		*(uint32_t *)0xFF600300 = val;
    180 }
    181 
    182 #if 0
    183 int
    184 power_cputype(void)
    185 {
    186 	uint32_t model;
    187 
    188 	model = iplinfo->model;
    189 	if (model & 0x08000000) {
    190 		/* ppc */
    191 		return 0;
    192 	} else if (model & 0x02000000)
    193 		return POWER_RSC;
    194 	else if (model & 0x04000000)
    195 		return POWER_2;
    196 	else
    197 		return POWER_1;
    198 }
    199 #endif
    200 
    201 
    202 void
    203 initppc(u_long startkernel, u_long endkernel, u_int args, void *btinfo)
    204 {
    205 	u_long ekern;
    206 	struct ipl_cb *r_iplcb;
    207 	struct ipl_directory *r_ipldir;
    208 	struct buc_info *bi;
    209 	int i;
    210 	register_t savemsr, msr;
    211 
    212 	/* indicate we have control */
    213 	//setled(0x40000000);
    214 	*(uint8_t *)0xe0000030 = '1';
    215 
    216 	/* copy bootinfo */
    217 	memcpy(bootinfo, btinfo, sizeof(bootinfo));
    218 	*(uint8_t *)0xe0000030 = '2';
    219 
    220 	/* copy iplcb data */
    221 	{
    222 		struct btinfo_iplcb *iplcbinfo;
    223 
    224 		iplcbinfo =
    225 		    (struct btinfo_iplcb *)lookup_bootinfo(BTINFO_IPLCB);
    226 		if (!iplcbinfo)
    227 			panic("no iplcb information found in bootinfo");
    228 
    229 		/* round_page endkernel, copy down to there, adjust */
    230 		ekern = round_page(endkernel);
    231 
    232 		r_iplcb = (struct ipl_cb *)iplcbinfo->addr;
    233 		r_ipldir = (struct ipl_directory *)&r_iplcb->dir;
    234 		memcpy((void *)ekern, r_iplcb, r_ipldir->cb_bitmap_size);
    235 		iplcb = (struct ipl_cb *)ekern;
    236 		ipldir = (struct ipl_directory *)&iplcb->dir;
    237 		iplinfo = (struct ipl_info *)((char *)iplcb +
    238 		    ipldir->iplinfo_off);
    239 		sysinfo = (struct sys_info *)((char *)iplcb +
    240 		    ipldir->sysinfo_offset);
    241 
    242 		ekern += r_ipldir->cb_bitmap_size;
    243 		endkernel = ekern;
    244 
    245 	}
    246 
    247 	/* IPLCB copydown successful */
    248 	setled(0x40100000);
    249 
    250 	/* Set memory region */
    251 	{
    252 		u_long memsize = iplinfo->ram_size;
    253 
    254 		/*
    255 		 * Some machines incorrectly report memory size in
    256 		 * MB.  Stupid stupid IBM breaking their own spec.
    257 		 * on conformant machines, it is:
    258 		 * The highest addressable real memory address byte+1
    259 		 */
    260 		if (memsize < 4069)
    261 			memsize = memsize * 1024 * 1024;
    262 		else
    263 			memsize -= 1;
    264 		physmemr[0].start = 0;
    265 		physmemr[0].size = memsize & ~PGOFSET;
    266 		availmemr[0].start = round_page(endkernel);
    267 		availmemr[0].size = memsize - availmemr[0].start;
    268 	}
    269 	avail_end = physmemr[0].start + physmemr[0].size;    /* XXX temporary */
    270 	*(uint8_t *)0xe0000030 = '3';
    271 
    272 #ifdef NOTYET
    273 	/* hrmm.. there is no timebase crap on POWER */
    274 	/*
    275 	 * Set CPU clock
    276 	 */
    277 	{
    278 		struct btinfo_clock *clockinfo;
    279 		extern u_long ticks_per_sec, ns_per_tick;
    280 
    281 		clockinfo =
    282 		    (struct btinfo_clock *)lookup_bootinfo(BTINFO_CLOCK);
    283 		if (!clockinfo)
    284 			panic("not found clock information in bootinfo");
    285 
    286 		ticks_per_sec = clockinfo->ticks_per_sec;
    287 		ns_per_tick = 1000000000 / ticks_per_sec;
    288 	}
    289 #endif
    290 	/* boothowto */
    291 	boothowto = args;
    292 
    293 	/*
    294 	 * Now setup fixed bat registers
    295 	 * 1) POWER has no bat registers.
    296 	 * 2) NVRAM, IPL ROM, and other fun bits all live at 0xFF000000 on the
    297 	 *    60x RS6000's, however if you try to map any less than 256MB
    298 	 *    on a 601 it wedges.
    299 	 */
    300 #if !defined(POWER)
    301 	setled(0x40200000);
    302 	oea_batinit(
    303 	    0xF0000000, BAT_BL_256M,
    304 /*
    305 	    RS6000_BUS_SPACE_MEM, BAT_BL_256M,
    306 	    RS6000_BUS_SPACE_IO,  BAT_BL_256M,
    307 	    0xbf800000, BAT_BL_8M,
    308 */
    309 	    0);
    310 	led_avail = 1;
    311 #endif
    312 	setled(0x40200000);
    313 
    314 	/* set the IO segreg for the first IOCC */
    315 #ifdef POWER
    316 	iosrtable[0xc] = 0x820C00E0;
    317 #else
    318 	iosrtable[0xc] = 0x82000080;
    319 #endif
    320 	__asm volatile ("mfmsr %0" : "=r"(savemsr));
    321 	msr = savemsr & ~PSL_DR;
    322 	__asm volatile ("mtmsr %0" : : "r"(msr));
    323 	__asm volatile ("mtsr 0xc,%0" : : "r"(iosrtable[0xc]));
    324 	__asm volatile ("mtmsr %0" : : "r"(msr|PSL_DR));
    325 	__asm volatile ("isync");
    326 	__asm volatile ("mtmsr %0;isync" : : "r"(savemsr));
    327 
    328 	cn_tab = &kcomcons;
    329 	printf("\nNetBSD/rs6000 booting ...\n");
    330 	setled(0x40300000);
    331 
    332 	/* Install vectors and interrupt handler. */
    333 	oea_init(NULL);
    334 	setled(0x40400000);
    335 
    336 	/* Initialize pmap module. */
    337 	uvm_md_init();
    338 	pmap_bootstrap(startkernel, endkernel);
    339 	setled(0x40500000);
    340 
    341 	/* populate the bucinfo stuff now that we can malloc */
    342 	bi = (struct buc_info *)((char *)iplcb + ipldir->bucinfo_off);
    343 	nrofbucs = bi->nrof_structs;
    344 	/*printf("nrof=%d\n", nrofbucs);*/
    345 	if (nrofbucs > MAX_BUCS)
    346 		aprint_error("WARNING: increase MAX_BUCS to at least %d\n",
    347 		    nrofbucs);
    348 	for (i=0; i < nrofbucs && i < MAX_BUCS; i++) {
    349 #ifdef DEBUG
    350 		printf("bi addr= %p\n", &bi);
    351 		printf("i=%d ssize=%x\n", i, bi->struct_size);
    352 #endif
    353 		bucinfo[i] = bi;
    354 		bi = (struct buc_info *)((char *)iplcb + ipldir->bucinfo_off +
    355 		    bi->struct_size);
    356 	}
    357 #ifdef DEBUG
    358 	printf("found %d bucs\n", nrofbucs);
    359 	for (i=0; i < nrofbucs; i++) {
    360 		printf("BUC type: %d\n", bucinfo[i]->dev_type);
    361 		printf("BUC cfg incr: %x\n", bucinfo[i]->cfg_addr_incr);
    362 		printf("BUC devid reg: %x\n", bucinfo[i]->device_id_reg);
    363 		printf("BUC iocc?= %d\n", bucinfo[i]->IOCC_flag);
    364 		printf("BUC location= %x%x%x%x\n", bucinfo[i]->location[0],
    365 		    bucinfo[i]->location[1], bucinfo[i]->location[2],
    366 		    bucinfo[i]->location[3]);
    367 	}
    368 	printf("sysinfo scr_addr %p -> %x\n", sysinfo->scr_addr,
    369 	    *sysinfo->scr_addr);
    370 #endif
    371 
    372 	/* Initialize bus_space. */
    373 	rs6000_bus_space_init();
    374 	setled(0x40600000);
    375 
    376 	/* Initialize the console */
    377 	consinit();
    378 	setled(0x41000000);
    379 
    380 #if NKSYMS || defined(DDB) || defined(MODULAR)
    381 	ksyms_addsyms_elf((int)((u_long)endsym - (u_long)startsym), startsym, endsym);
    382 #endif
    383 
    384 #ifdef DDB
    385 	if (boothowto & RB_KDB)
    386 		Debugger();
    387 #endif
    388 }
    389 
    390 void
    391 mem_regions(struct mem_region **mem, struct mem_region **avail)
    392 {
    393 
    394 	*mem = physmemr;
    395 	*avail = availmemr;
    396 }
    397 
    398 static void
    399 init_intr(void)
    400 {
    401 	pic_init();
    402 	pic_iocc = setup_iocc();
    403 	oea_install_extint(pic_ext_intr);
    404 }
    405 
    406 /*
    407  * Machine dependent startup code.
    408  */
    409 void
    410 cpu_startup(void)
    411 {
    412 	/* 420 indicates we are entering cpu_startup() */
    413 	setled(0x42000000);
    414 	/* Do common startup. */
    415 	oea_startup("rs6000");
    416 
    417 	/*
    418 	 * Initialize the IOCC interrupt stuff
    419 	 */
    420 	init_intr();
    421 
    422 	/*
    423 	 * Now allow hardware interrupts.
    424 	 */
    425 	{
    426 		int msr;
    427 
    428 		splraise(-1);
    429 		__asm volatile ("mfmsr %0; ori %0,%0,%1; mtmsr %0"
    430 			      : "=r"(msr) : "K"(PSL_EE));
    431 		setled(0x42200000);
    432 	}
    433 	/*
    434 	 * Now safe for bus space allocation to use malloc.
    435 	 */
    436 	bus_space_mallocok();
    437 }
    438 
    439 /*
    440  * lookup_bootinfo:
    441  * Look up information in bootinfo of boot loader.
    442  */
    443 void *
    444 lookup_bootinfo(int type)
    445 {
    446 	struct btinfo_common *bt;
    447 	struct btinfo_common *help = (struct btinfo_common *)bootinfo;
    448 
    449 	do {
    450 		bt = help;
    451 		if (bt->type == type)
    452 			return (help);
    453 		help = (struct btinfo_common *)((char*)help + bt->next);
    454 	} while (bt->next &&
    455 		(size_t)help < (size_t)bootinfo + sizeof (bootinfo));
    456 
    457 	return (NULL);
    458 }
    459 
    460 /*
    461  * Reboot an RS6K
    462  */
    463 static void
    464 reset_rs6000(void)
    465 {
    466 	mtmsr(mfmsr() | PSL_IP);
    467 
    468 	/* writing anything to the power/reset reg on an rs6k will cause
    469 	 * a soft reboot. Supposedly.
    470 	 */
    471 	if (sysinfo->prcr_addr)
    472 		outb(sysinfo->prcr_addr, 0x1);
    473 }
    474 
    475 /*
    476  * Halt or reboot the machine after syncing/dumping according to howto.
    477  */
    478 void
    479 cpu_reboot(int howto, char *what)
    480 {
    481 	static int syncing;
    482 
    483 	if (cold) {
    484 		howto |= RB_HALT;
    485 		goto halt_sys;
    486 	}
    487 
    488 	boothowto = howto;
    489 	if ((howto & RB_NOSYNC) == 0 && syncing == 0) {
    490 		syncing = 1;
    491 		vfs_shutdown();		/* sync */
    492 		//resettodr();		/* set wall clock */
    493 	}
    494 
    495 	/* Disable intr */
    496 	splhigh();
    497 
    498 	/* Do dump if requested */
    499 	if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP)
    500 		oea_dumpsys();
    501 
    502 halt_sys:
    503 	doshutdownhooks();
    504 
    505 	pmf_system_shutdown(boothowto);
    506 
    507 	if (howto & RB_HALT) {
    508                 printf("\n");
    509                 printf("The operating system has halted.\n");
    510                 printf("Please press any key to reboot.\n\n");
    511                 cnpollc(true);	/* for proper keyboard command handling */
    512                 cngetc();
    513                 cnpollc(false);
    514 	}
    515 
    516 	printf("rebooting...\n\n");
    517 
    518 	reset_rs6000();
    519 
    520 	for (;;)
    521 		continue;
    522 	/* NOTREACHED */
    523 }
    524 
    525 /* The iocc0 mapping is set by init_ppc to 0xC via an iosegreg */
    526 struct powerpc_bus_space rs6000_iocc0_io_space_tag = {
    527 	.pbs_flags = _BUS_SPACE_LITTLE_ENDIAN|_BUS_SPACE_IO_TYPE,
    528 	.pbs_offset = 0xC0000000,
    529 	.pbs_base = 0x00000000,
    530 	.pbs_limit = 0x10000000,
    531 };
    532 
    533 static char ex_storage[2][EXTENT_FIXED_STORAGE_SIZE(8)]
    534     __attribute__((aligned(8)));
    535 
    536 void
    537 rs6000_bus_space_init(void)
    538 {
    539 	int error;
    540 
    541 	error = bus_space_init(&rs6000_iocc0_io_space_tag, "ioport",
    542 	    ex_storage[0], sizeof(ex_storage[0]));
    543 	if (error)
    544 		panic("rs6000_bus_space_init: can't init io tag");
    545 
    546 #if 0
    547 	error = extent_alloc_region(rs6000_iocc0_io_space_tag.pbs_extent,
    548 	    0x10000, 0x7F0000, EX_NOWAIT);
    549 	if (error)
    550 		panic("rs6000_bus_space_init: can't block out reserved I/O"
    551 		    " space 0x10000-0x7fffff: error=%d", error);
    552 	error = bus_space_init(&prep_mem_space_tag, "iomem",
    553 	    ex_storage[1], sizeof(ex_storage[1]));
    554 	if (error)
    555 		panic("prep_bus_space_init: can't init mem tag");
    556 
    557 	rs6000_iocc0_io_space_tag.pbs_extent = prep_io_space_tag.pbs_extent;
    558 	error = bus_space_init(&prep_isa_io_space_tag, "isa-ioport", NULL, 0);
    559 	if (error)
    560 		panic("prep_bus_space_init: can't init isa io tag");
    561 
    562 	prep_isa_mem_space_tag.pbs_extent = prep_mem_space_tag.pbs_extent;
    563 	error = bus_space_init(&prep_isa_mem_space_tag, "isa-iomem", NULL, 0);
    564 	if (error)
    565 		panic("prep_bus_space_init: can't init isa mem tag");
    566 #endif
    567 }
    568 
    569 static bus_space_handle_t kcom_base = (bus_space_handle_t) (0xc0000000 + CONCOMADDR);
    570 extern void bsw1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, u_int8_t v);
    571 extern int bsr1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o);
    572 #define KCOM_GETBYTE(r)         bsr1(0, kcom_base, (r))
    573 #define KCOM_PUTBYTE(r,v)       bsw1(0, kcom_base, (r), (v))
    574 
    575 static int
    576 kcomcngetc(dev_t dev)
    577 {
    578         int stat, c;
    579 	register_t msr;
    580 
    581 	msr = mfmsr();
    582 	mtmsr(msr|PSL_DR);
    583 	__asm volatile ("isync");
    584 
    585         /* block until a character becomes available */
    586         while (!ISSET(stat = KCOM_GETBYTE(com_lsr), LSR_RXRDY))
    587                 ;
    588 
    589         c = KCOM_GETBYTE(com_data);
    590         stat = KCOM_GETBYTE(com_iir);
    591 	mtmsr(msr);
    592 	__asm volatile ("isync");
    593         return c;
    594 }
    595 
    596 /*
    597  * Console kernel output character routine.
    598  */
    599 static void
    600 kcomcnputc(dev_t dev, int c)
    601 {
    602         int timo;
    603 	register_t msr;
    604 
    605 	msr = mfmsr();
    606 	mtmsr(msr|PSL_DR);
    607 	__asm volatile ("isync");
    608         /* wait for any pending transmission to finish */
    609         timo = 150000;
    610         while (!ISSET(KCOM_GETBYTE(com_lsr), LSR_TXRDY) && --timo)
    611                 continue;
    612 
    613         KCOM_PUTBYTE(com_data, c);
    614 
    615         /* wait for this transmission to complete */
    616         timo = 1500000;
    617         while (!ISSET(KCOM_GETBYTE(com_lsr), LSR_TXRDY) && --timo)
    618                 continue;
    619 	mtmsr(msr);
    620 	__asm volatile ("isync");
    621 }
    622 
    623 static void
    624 kcomcnpollc(dev_t dev, int on)
    625 {
    626 }
    627 
    628 struct consdev kcomcons = {
    629         NULL, NULL, kcomcngetc, kcomcnputc, kcomcnpollc, NULL,
    630         NULL, NULL, NODEV, CN_NORMAL
    631 };
    632