1 /* $NetBSD: fdtbus.c,v 1.2 2015/12/16 19:33:16 jmcneill Exp $ */ 2 3 /*- 4 * Copyright (c) 2015 Jared D. McNeill <jmcneill@invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: fdtbus.c,v 1.2 2015/12/16 19:33:16 jmcneill Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/device.h> 35 #include <sys/kmem.h> 36 37 #include <sys/bus.h> 38 39 #include <dev/ofw/openfirm.h> 40 41 #include <dev/fdt/fdtvar.h> 42 43 static int fdt_match(device_t, cfdata_t, void *); 44 static void fdt_attach(device_t, device_t, void *); 45 static void fdt_scan(device_t, const struct fdt_attach_args *, const char *); 46 static bool fdt_is_init(const struct fdt_attach_args *, const char *); 47 48 CFATTACH_DECL_NEW(fdt, 0, 49 fdt_match, fdt_attach, NULL, NULL); 50 51 static int fdt_print(void *, const char *); 52 53 static int 54 fdt_match(device_t parent, cfdata_t cf, void *aux) 55 { 56 const struct fdt_attach_args *faa = aux; 57 58 if (!OF_child(faa->faa_phandle)) 59 return 0; 60 61 return 1; 62 } 63 64 static void 65 fdt_attach(device_t parent, device_t self, void *aux) 66 { 67 const struct fdt_attach_args *faa = aux; 68 const int phandle = faa->faa_phandle; 69 char *model; 70 int len, n; 71 72 aprint_naive("\n"); 73 len = OF_getproplen(phandle, "model"); 74 if (len > 0) { 75 model = kmem_zalloc(len, KM_SLEEP); 76 if (OF_getprop(phandle, "model", model, len) == len) { 77 aprint_normal(": %s\n", model); 78 } else { 79 aprint_normal("\n"); 80 } 81 kmem_free(model, len); 82 } else { 83 aprint_normal("\n"); 84 } 85 86 for (n = 0; n < faa->faa_ninit; n++) { 87 fdt_scan(self, faa, faa->faa_init[n]); 88 } 89 fdt_scan(self, faa, NULL); 90 } 91 92 static void 93 fdt_scan(device_t self, const struct fdt_attach_args *faa, const char *devname) 94 { 95 const int phandle = faa->faa_phandle; 96 int len, alen, child; 97 char *name, *status; 98 99 for (child = OF_child(phandle); child; child = OF_peer(child)) { 100 struct fdt_attach_args nfaa = *faa; 101 nfaa.faa_phandle = child; 102 103 /* Only attach to nodes with a compatible property */ 104 len = OF_getproplen(child, "compatible"); 105 if (len <= 0) 106 continue; 107 108 /* If there is a "status" property, make sure it is "okay" */ 109 len = OF_getproplen(child, "status"); 110 if (len > 0) { 111 status = kmem_zalloc(len, KM_SLEEP); 112 alen = OF_getprop(child, "status", status, len); 113 KASSERT(alen == len); 114 const bool okay_p = strcmp(status, "okay") == 0 || 115 strcmp(status, "ok") == 0; 116 kmem_free(status, len); 117 if (!okay_p) { 118 continue; 119 } 120 } 121 122 /* Attach the device */ 123 len = OF_getproplen(child, "name"); 124 if (len <= 0) { 125 continue; 126 } 127 name = kmem_zalloc(len, KM_SLEEP); 128 if (OF_getprop(child, "name", name, len) == len) { 129 nfaa.faa_name = name; 130 if ((devname != NULL && strcmp(name, devname) == 0) || 131 (devname == NULL && !fdt_is_init(faa, name))) { 132 config_found(self, &nfaa, fdt_print); 133 } 134 } 135 kmem_free(name, len); 136 } 137 } 138 139 static bool 140 fdt_is_init(const struct fdt_attach_args *faa, const char *devname) 141 { 142 u_int n; 143 144 for (n = 0; n < faa->faa_ninit; n++) { 145 if (strcmp(faa->faa_init[n], devname) == 0) 146 return true; 147 } 148 149 return false; 150 } 151 152 static int 153 fdt_print(void *aux, const char *pnp) 154 { 155 const struct fdt_attach_args * const faa = aux; 156 157 if (pnp) { 158 aprint_normal("%s at %s", faa->faa_name, pnp); 159 } 160 161 return UNCONF; 162 } 163