/*-
* Copyright (c) 1996 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Gordon W. Ross.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Hooks for kgdb when attached via the z8530 driver
*
* To use this, build a kernel with: option KGDB, and
* boot that kernel with "-d". (The kernel will call
* zs_kgdb_init, kgdb_connect.) When the console prints
* "kgdb waiting..." you run "gdb -k kernel" and do:
* (gdb) set remotebaud 19200
* (gdb) target remote /dev/ttyb
*/
/*
* Set up for kgdb; called at boot time before configuration.
* KGDB interrupts will be enabled later when zs0 is configured.
* Called after cninit(), so printf() etc. works.
*/
void
zs_kgdb_init(void)
{
struct zs_chanstate cs;
struct zsdevice *zsd;
volatile struct zschan *zc;
int channel, promzs_unit;
extern const struct cdevsw zstty_cdevsw;
/* printf("zs_kgdb_init: kgdb_dev=0x%x\n", kgdb_dev); */
if (cdevsw_lookup(kgdb_dev) != &zstty_cdevsw)
return;
/* Note: (ttya,ttyb) on zs0, and (ttyc,ttyd) on zs2 */
promzs_unit = (kgdb_dev & 2) ? 2 : 0;
channel = kgdb_dev & 1;
printf("zs_kgdb_init: attaching Serial(%lld) at %d baud\n",
(kgdb_dev & 3), kgdb_rate);
/* Now set parameters. (interrupts disabled) */
zs_setparam(&cs, 0, kgdb_rate);
/* Store the getc/putc functions and arg. */
kgdb_attach(zs_getc, zs_putc, __UNVOLATILE(zc));
}
/*
* This is a "hook" called by zstty_attach to allow the tty
* to be "taken over" for exclusive use by kgdb.
* Return non-zero if this is the kgdb port.
*
* Set the speed to kgdb_rate, CS8, etc.
*/
int
zs_check_kgdb(struct zs_chanstate *cs, int dev)
{
if (dev != kgdb_dev)
return (0);
/*
* Yes, this is port in use by kgdb.
*/
cs->cs_private = NULL;
cs->cs_ops = &zsops_kgdb;
/* Now set parameters. (interrupts enabled) */
zs_setparam(cs, 1, kgdb_rate);
return (1);
}
/*
* KGDB framing character received: enter kernel debugger. This probably
* should time out after a few seconds to avoid hanging on spurious input.
*/
void
zskgdb(struct zs_chanstate *cs)
{
int unit = minor(kgdb_dev);
printf("zstty%d: kgdb interrupt\n", unit);
/* This will trap into the debugger. */
kgdb_connect(1);
}
/****************************************************************
* Interface to the lower layer (zscc)
****************************************************************/
/*
* findzs() should return the address of the given zs channel.
* Here we count on the PROM to map in the required zs chips.
*/
static void *
findzs(int zs)
{
#if defined(SUN4)
if (CPU_ISSUN4) {
/*
* On sun4, we use hard-coded physical addresses
*/
#define ZS0_PHYS 0xf1000000
#define ZS1_PHYS 0xf0000000
#define ZS2_PHYS 0xe0000000
bus_space_handle_t bh;
bus_addr_t paddr;
switch (zs) {
case 0:
paddr = ZS0_PHYS;
break;
case 1:
paddr = ZS1_PHYS;
break;
case 2:
paddr = ZS2_PHYS;
break;
default:
return (NULL);
}
if (cpuinfo.cpu_type == CPUTYP_4_100)
/* Clear top bits of physical address on 4/100 */
paddr &= ~0xf0000000;
/*
* Have the obio module figure out which virtual
* address the device is mapped to.
*/
if (obio_find_rom_map(paddr, PAGE_SIZE, &bh) != 0)
return (NULL);
return ((void *)bh);
}
#endif
#if defined(SUN4C) || defined(SUN4M)
if (CPU_ISSUN4C || CPU_ISSUN4M) {
int node;
node = firstchild(findroot());
if (CPU_ISSUN4M) {
/*
* On sun4m machines zs is in "obio" tree.
*/
node = findnode(node, "obio");
if (node == 0)
panic("findzs: no obio node");
node = firstchild(node);
}
while ((node = findnode(node, "zs")) != 0) {
int nvaddrs, *vaddrs, vstore[10];