ofwbus.c revision 94755
1/* 2 * Copyright 1998 Massachusetts Institute of Technology 3 * 4 * Permission to use, copy, modify, and distribute this software and 5 * its documentation for any purpose and without fee is hereby 6 * granted, provided that both the above copyright notice and this 7 * permission notice appear in all copies, that both the above 8 * copyright notice and this permission notice appear in all 9 * supporting documentation, and that the name of M.I.T. not be used 10 * in advertising or publicity pertaining to distribution of the 11 * software without specific, written prior permission. M.I.T. makes 12 * no representations about the suitability of this software for any 13 * purpose. It is provided "as is" without express or implied 14 * warranty. 15 * 16 * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 17 * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 20 * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 23 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 26 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29/*- 30 * Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>. All rights reserved. 31 * 32 * Redistribution and use in source and binary forms, with or without 33 * modification, are permitted provided that the following conditions 34 * are met: 35 * 1. Redistributions of source code must retain the above copyright 36 * notice, this list of conditions and the following disclaimer. 37 * 2. Redistributions in binary form must reproduce the above copyright 38 * notice, this list of conditions and the following disclaimer in the 39 * documentation and/or other materials provided with the distribution. 40 * 41 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * from: FreeBSD: src/sys/i386/i386/nexus.c,v 1.43 2001/02/09 54 * 55 * $FreeBSD: head/sys/powerpc/aim/nexus.c 94755 2002-04-15 12:29:18Z benno $ 56 */ 57 58#include <sys/param.h> 59#include <sys/systm.h> 60#include <sys/bus.h> 61#include <sys/cons.h> 62#include <sys/kernel.h> 63#include <sys/malloc.h> 64 65#include <dev/ofw/openfirm.h> 66 67#include <machine/bus.h> 68#include <machine/frame.h> 69#include <machine/nexusvar.h> 70#include <machine/resource.h> 71 72/* 73 * The nexus (which is a pseudo-bus actually) iterates over the nodes that 74 * exist in OpenFirmware and adds them as devices to this bus so that drivers 75 * can be attached to them. 76 * 77 * Maybe this code should get into dev/ofw to some extent, as some of it should 78 * work for all OpenFirmware based machines... 79 */ 80 81static MALLOC_DEFINE(M_NEXUS, "nexus", "nexus device information"); 82 83struct nexus_devinfo { 84 phandle_t ndi_node; 85 /* Some common properties. */ 86 char *ndi_name; 87 char *ndi_device_type; 88}; 89 90struct nexus_softc { 91}; 92 93static int nexus_probe(device_t); 94static void nexus_probe_nomatch(device_t, device_t); 95static int nexus_read_ivar(device_t, device_t, int, uintptr_t *); 96static int nexus_write_ivar(device_t, device_t, int, uintptr_t); 97 98static device_method_t nexus_methods[] = { 99 /* Device interface */ 100 DEVMETHOD(device_probe, nexus_probe), 101 DEVMETHOD(device_attach, bus_generic_attach), 102 DEVMETHOD(device_detach, bus_generic_detach), 103 DEVMETHOD(device_shutdown, bus_generic_shutdown), 104 DEVMETHOD(device_suspend, bus_generic_suspend), 105 DEVMETHOD(device_resume, bus_generic_resume), 106 107 /* Bus interface. Resource management is business of the children... */ 108 DEVMETHOD(bus_print_child, bus_generic_print_child), 109 DEVMETHOD(bus_probe_nomatch, nexus_probe_nomatch), 110 DEVMETHOD(bus_read_ivar, nexus_read_ivar), 111 DEVMETHOD(bus_write_ivar, nexus_write_ivar), 112 113 { 0, 0 } 114}; 115 116static driver_t nexus_driver = { 117 "nexus", 118 nexus_methods, 119 sizeof(struct nexus_softc), 120}; 121 122static devclass_t nexus_devclass; 123 124DRIVER_MODULE(nexus, root, nexus_driver, nexus_devclass, 0, 0); 125 126static int 127nexus_probe(device_t dev) 128{ 129 phandle_t root; 130 phandle_t child, new_node, temp_node; 131 device_t cdev; 132 struct nexus_devinfo *dinfo; 133 struct nexus_softc *sc; 134 char *name, *type; 135 136 if ((root = OF_peer(0)) == -1) 137 panic("nexus_probe: OF_peer failed."); 138 139 child = root; 140 while (child != 0) { 141 OF_getprop_alloc(child, "name", 1, (void **)&name); 142 OF_getprop_alloc(child, "device_type", 1, (void **)&type); 143 cdev = device_add_child(dev, NULL, -1); 144 if (cdev != NULL) { 145 dinfo = malloc(sizeof(*dinfo), M_NEXUS, M_WAITOK); 146 dinfo->ndi_node = child; 147 dinfo->ndi_name = name; 148 dinfo->ndi_device_type = type; 149 device_set_ivars(cdev, dinfo); 150 } else 151 free(name, M_OFWPROP); 152 153next: 154 new_node = OF_child(child); 155 if (new_node == -1) 156 panic("nexus_probe: OF_child return -1"); 157 if (new_node == 0) 158 new_node = OF_peer(child); 159 if (new_node == 0) { 160 temp_node = child; 161 while (new_node == 0) { 162 temp_node = OF_parent(temp_node); 163 if (temp_node == 0) 164 break; 165 new_node = OF_peer(temp_node); 166 } 167 } 168 child = new_node; 169 } 170 device_set_desc(dev, "OpenFirmware Nexus device"); 171 return (0); 172} 173 174static void 175nexus_probe_nomatch(device_t dev, device_t child) 176{ 177 char *name, *type; 178 179 if (BUS_READ_IVAR(dev, child, NEXUS_IVAR_NAME, 180 (uintptr_t *)&name) != 0 || 181 BUS_READ_IVAR(dev, child, NEXUS_IVAR_DEVICE_TYPE, 182 (uintptr_t *)&type) != 0) 183 return; 184 185 if (type == NULL) 186 type = "(unknown)"; 187#if 0 188 device_printf(dev, "<%s>, type %s (no driver attached)\n", 189 name, type); 190#endif 191} 192 193static int 194nexus_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 195{ 196 struct nexus_devinfo *dinfo; 197 198 if ((dinfo = device_get_ivars(child)) == 0) 199 return (ENOENT); 200 switch (which) { 201 case NEXUS_IVAR_NODE: 202 *result = dinfo->ndi_node; 203 break; 204 case NEXUS_IVAR_NAME: 205 *result = (uintptr_t)dinfo->ndi_name; 206 break; 207 case NEXUS_IVAR_DEVICE_TYPE: 208 *result = (uintptr_t)dinfo->ndi_device_type; 209 break; 210 default: 211 return (ENOENT); 212 } 213 return 0; 214} 215 216static int 217nexus_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 218{ 219 struct nexus_devinfo *dinfo; 220 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