ofwbus.c revision 94755
121890Sobrien/* 221890Sobrien * Copyright 1998 Massachusetts Institute of Technology 321890Sobrien * 421890Sobrien * Permission to use, copy, modify, and distribute this software and 521890Sobrien * its documentation for any purpose and without fee is hereby 621890Sobrien * granted, provided that both the above copyright notice and this 721890Sobrien * permission notice appear in all copies, that both the above 821890Sobrien * copyright notice and this permission notice appear in all 921890Sobrien * supporting documentation, and that the name of M.I.T. not be used 1021890Sobrien * in advertising or publicity pertaining to distribution of the 1121890Sobrien * software without specific, written prior permission. M.I.T. makes 1221890Sobrien * no representations about the suitability of this software for any 1321890Sobrien * purpose. It is provided "as is" without express or implied 1421890Sobrien * warranty. 1521890Sobrien * 1621890Sobrien * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 1721890Sobrien * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 1821890Sobrien * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 1921890Sobrien * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 2021890Sobrien * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2121890Sobrien * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2221890Sobrien * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 2321890Sobrien * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 2421890Sobrien * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2521890Sobrien * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 2650476Speter * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2721890Sobrien * SUCH DAMAGE. 28215907Smarius */ 2953200Sphantom/*- 3079538Sru * Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>. All rights reserved. 3121890Sobrien * 3221890Sobrien * Redistribution and use in source and binary forms, with or without 33148145Strhodes * modification, are permitted provided that the following conditions 3421890Sobrien * are met: 35151046Strhodes * 1. Redistributions of source code must retain the above copyright 36151046Strhodes * notice, this list of conditions and the following disclaimer. 37148220Strhodes * 2. Redistributions in binary form must reproduce the above copyright 38148145Strhodes * notice, this list of conditions and the following disclaimer in the 3986992Sjdp * documentation and/or other materials provided with the distribution. 4056460Sasmodai * 41148145Strhodes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 42148145Strhodes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43151046Strhodes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44151046Strhodes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45148145Strhodes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46148145Strhodes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47148145Strhodes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48148145Strhodes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 4921890Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5021890Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5121890Sobrien * SUCH DAMAGE. 52129070Ssimon * 53129070Ssimon * from: FreeBSD: src/sys/i386/i386/nexus.c,v 1.43 2001/02/09 54186126Sbrueffer * 55186126Sbrueffer * $FreeBSD: head/sys/powerpc/aim/nexus.c 94755 2002-04-15 12:29:18Z benno $ 56186126Sbrueffer */ 57186126Sbrueffer 58186126Sbrueffer#include <sys/param.h> 59186126Sbrueffer#include <sys/systm.h> 60186126Sbrueffer#include <sys/bus.h> 6127402Sobrien#include <sys/cons.h> 6230002Sdg#include <sys/kernel.h> 6330002Sdg#include <sys/malloc.h> 6430002Sdg 65207971Syongari#include <dev/ofw/openfirm.h> 66207971Syongari 67207971Syongari#include <machine/bus.h> 68207971Syongari#include <machine/frame.h> 69207971Syongari#include <machine/nexusvar.h> 70207971Syongari#include <machine/resource.h> 71207971Syongari 72207971Syongari/* 73207971Syongari * The nexus (which is a pseudo-bus actually) iterates over the nodes that 7427402Sobrien * exist in OpenFirmware and adds them as devices to this bus so that drivers 7530002Sdg * can be attached to them. 7630002Sdg * 7730002Sdg * Maybe this code should get into dev/ofw to some extent, as some of it should 7830002Sdg * work for all OpenFirmware based machines... 79207971Syongari */ 80207971Syongari 81207971Syongaristatic MALLOC_DEFINE(M_NEXUS, "nexus", "nexus device information"); 82207971Syongari 83207971Syongaristruct nexus_devinfo { 8430002Sdg phandle_t ndi_node; 8530002Sdg /* Some common properties. */ 86102366Sbmah char *ndi_name; 8748218Smph char *ndi_device_type; 8830002Sdg}; 8985463Sjlemon 9085463Sjlemonstruct nexus_softc { 9185463Sjlemon}; 92141046Syar 93141046Syarstatic int nexus_probe(device_t); 94141046Syarstatic void nexus_probe_nomatch(device_t, device_t); 95141046Syarstatic int nexus_read_ivar(device_t, device_t, int, uintptr_t *); 96141046Syarstatic int nexus_write_ivar(device_t, device_t, int, uintptr_t); 97141046Syar 98141046Syarstatic device_method_t nexus_methods[] = { 99141046Syar /* Device interface */ 100141046Syar DEVMETHOD(device_probe, nexus_probe), 101141046Syar DEVMETHOD(device_attach, bus_generic_attach), 102141046Syar DEVMETHOD(device_detach, bus_generic_detach), 103141046Syar DEVMETHOD(device_shutdown, bus_generic_shutdown), 104141046Syar DEVMETHOD(device_suspend, bus_generic_suspend), 10585463Sjlemon DEVMETHOD(device_resume, bus_generic_resume), 10685463Sjlemon 10785463Sjlemon /* Bus interface. Resource management is business of the children... */ 10885463Sjlemon DEVMETHOD(bus_print_child, bus_generic_print_child), 10986671Sru DEVMETHOD(bus_probe_nomatch, nexus_probe_nomatch), 110117666Srushani DEVMETHOD(bus_read_ivar, nexus_read_ivar), 11186671Sru DEVMETHOD(bus_write_ivar, nexus_write_ivar), 11285463Sjlemon 11385463Sjlemon { 0, 0 } 11485463Sjlemon}; 11586671Sru 11685463Sjlemonstatic driver_t nexus_driver = { 117131570Ssimon "nexus", 118131570Ssimon nexus_methods, 119131570Ssimon sizeof(struct nexus_softc), 120131570Ssimon}; 121131570Ssimon 122131570Ssimonstatic devclass_t nexus_devclass; 123131570Ssimon 124131570SsimonDRIVER_MODULE(nexus, root, nexus_driver, nexus_devclass, 0, 0); 125131570Ssimon 126131570Ssimonstatic int 127131570Ssimonnexus_probe(device_t dev) 128131570Ssimon{ 129131570Ssimon phandle_t root; 130131570Ssimon phandle_t child, new_node, temp_node; 131131570Ssimon device_t cdev; 132131570Ssimon struct nexus_devinfo *dinfo; 133131570Ssimon struct nexus_softc *sc; 134165873Sdelphij char *name, *type; 135165873Sdelphij 136131570Ssimon if ((root = OF_peer(0)) == -1) 137131570Ssimon panic("nexus_probe: OF_peer failed."); 138131570Ssimon 139131570Ssimon child = root; 140131570Ssimon while (child != 0) { 141131570Ssimon OF_getprop_alloc(child, "name", 1, (void **)&name); 142131570Ssimon OF_getprop_alloc(child, "device_type", 1, (void **)&type); 143131570Ssimon cdev = device_add_child(dev, NULL, -1); 144131570Ssimon if (cdev != NULL) { 145131570Ssimon dinfo = malloc(sizeof(*dinfo), M_NEXUS, M_WAITOK); 146131570Ssimon dinfo->ndi_node = child; 147131570Ssimon dinfo->ndi_name = name; 148207971Syongari dinfo->ndi_device_type = type; 149207971Syongari device_set_ivars(cdev, dinfo); 150207971Syongari } else 151207971Syongari free(name, M_OFWPROP); 152207971Syongari 153207971Syongarinext: 154207971Syongari new_node = OF_child(child); 155207971Syongari if (new_node == -1) 156207971Syongari panic("nexus_probe: OF_child return -1"); 157207971Syongari if (new_node == 0) 158207971Syongari new_node = OF_peer(child); 159207971Syongari if (new_node == 0) { 160207971Syongari temp_node = child; 161207971Syongari while (new_node == 0) { 162207971Syongari temp_node = OF_parent(temp_node); 163207971Syongari if (temp_node == 0) 164207971Syongari break; 165207971Syongari new_node = OF_peer(temp_node); 166207971Syongari } 167207971Syongari } 168207971Syongari child = new_node; 169207971Syongari } 170207971Syongari device_set_desc(dev, "OpenFirmware Nexus device"); 171207971Syongari return (0); 172207971Syongari} 173207971Syongari 174207971Syongaristatic void 175207971Syongarinexus_probe_nomatch(device_t dev, device_t child) 176207971Syongari{ 177207971Syongari char *name, *type; 178207971Syongari 179207971Syongari if (BUS_READ_IVAR(dev, child, NEXUS_IVAR_NAME, 180207971Syongari (uintptr_t *)&name) != 0 || 181207971Syongari BUS_READ_IVAR(dev, child, NEXUS_IVAR_DEVICE_TYPE, 18221890Sobrien (uintptr_t *)&type) != 0) 18321890Sobrien return; 18421890Sobrien 18521890Sobrien if (type == NULL) 18621890Sobrien type = "(unknown)"; 18721890Sobrien#if 0 18821890Sobrien device_printf(dev, "<%s>, type %s (no driver attached)\n", 18921890Sobrien name, type); 19021890Sobrien#endif 19121890Sobrien} 19221890Sobrien 19385463Sjlemonstatic int 19485463Sjlemonnexus_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 19589610Smpp{ 19621890Sobrien struct nexus_devinfo *dinfo; 19721890Sobrien 198166346Sbrueffer if ((dinfo = device_get_ivars(child)) == 0) 19921890Sobrien return (ENOENT); 200110946Strhodes switch (which) { 20179727Sschweikh case NEXUS_IVAR_NODE: 20259974Sarchie *result = dinfo->ndi_node; 203138068Sbrueffer break; 204141046Syar case NEXUS_IVAR_NAME: 20559974Sarchie *result = (uintptr_t)dinfo->ndi_name; 20621890Sobrien break; 20721890Sobrien case NEXUS_IVAR_DEVICE_TYPE: 20821890Sobrien *result = (uintptr_t)dinfo->ndi_device_type; 20921890Sobrien break; 21021890Sobrien default: 21121890Sobrien return (ENOENT); 21269027Sru } 21321890Sobrien return 0; 21421890Sobrien} 21534504Scharnier 21634504Scharnierstatic int 217113535Smuxnexus_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 218113535Smux{ 21934504Scharnier struct nexus_devinfo *dinfo; 22034504Scharnier 221 if ((dinfo = device_get_ivars(child)) == 0) 222 return (ENOENT); 223 224 switch (which) { 225 case NEXUS_IVAR_NODE: 226 case NEXUS_IVAR_NAME: 227 case NEXUS_IVAR_DEVICE_TYPE: 228 return (EINVAL); 229 default: 230 return (ENOENT); 231 } 232 return 0; 233} 234