1f9f848faSopenharmony_ci/*- 2f9f848faSopenharmony_ci * SPDX-License-Identifier: BSD-2-Clause 3f9f848faSopenharmony_ci * 4f9f848faSopenharmony_ci * Copyright (c) 1997,1998,2003 Doug Rabson 5f9f848faSopenharmony_ci * All rights reserved. 6f9f848faSopenharmony_ci * 7f9f848faSopenharmony_ci * Redistribution and use in source and binary forms, with or without 8f9f848faSopenharmony_ci * modification, are permitted provided that the following conditions 9f9f848faSopenharmony_ci * are met: 10f9f848faSopenharmony_ci * 1. Redistributions of source code must retain the above copyright 11f9f848faSopenharmony_ci * notice, this list of conditions and the following disclaimer. 12f9f848faSopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 13f9f848faSopenharmony_ci * notice, this list of conditions and the following disclaimer in the 14f9f848faSopenharmony_ci * documentation and/or other materials provided with the distribution. 15f9f848faSopenharmony_ci * 16f9f848faSopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17f9f848faSopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18f9f848faSopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19f9f848faSopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20f9f848faSopenharmony_ci * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21f9f848faSopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22f9f848faSopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23f9f848faSopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24f9f848faSopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25f9f848faSopenharmony_ci * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26f9f848faSopenharmony_ci * SUCH DAMAGE. 27f9f848faSopenharmony_ci */ 28f9f848faSopenharmony_ci 29f9f848faSopenharmony_ci#include <sys/cdefs.h> 30f9f848faSopenharmony_ci 31f9f848faSopenharmony_ci#include <sys/param.h> 32f9f848faSopenharmony_ci#include <sys/kobj.h> 33f9f848faSopenharmony_ci#include <sys/malloc.h> 34f9f848faSopenharmony_ci#include <sys/queue.h> 35f9f848faSopenharmony_ci#include <sys/systm.h> 36f9f848faSopenharmony_ci#include <sys/bus.h> 37f9f848faSopenharmony_ci#include <sys/mutex.h> 38f9f848faSopenharmony_ci#include "los_hwi.h" 39f9f848faSopenharmony_ci 40f9f848faSopenharmony_ci#ifndef BOOTVERBOSE 41f9f848faSopenharmony_ci#define BOOTVERBOSE 0 42f9f848faSopenharmony_ci#endif 43f9f848faSopenharmony_ciint bootverbose = BOOTVERBOSE; 44f9f848faSopenharmony_ci 45f9f848faSopenharmony_ci/* 46f9f848faSopenharmony_ci * * Used to attach drivers to devclasses. 47f9f848faSopenharmony_ci * */ 48f9f848faSopenharmony_citypedef struct driverlink *driverlink_t; 49f9f848faSopenharmony_cistruct driverlink { 50f9f848faSopenharmony_ci kobj_class_t driver; 51f9f848faSopenharmony_ci TAILQ_ENTRY(driverlink) link; /* list of drivers in devclass */ 52f9f848faSopenharmony_ci int pass; 53f9f848faSopenharmony_ci TAILQ_ENTRY(driverlink) passlink; 54f9f848faSopenharmony_ci}; 55f9f848faSopenharmony_ci 56f9f848faSopenharmony_ci/* 57f9f848faSopenharmony_ci * Forward declarations 58f9f848faSopenharmony_ci */ 59f9f848faSopenharmony_citypedef TAILQ_HEAD(devclass_list, devclass) devclass_list_t; 60f9f848faSopenharmony_citypedef TAILQ_HEAD(driver_list, driverlink) driver_list_t; 61f9f848faSopenharmony_citypedef TAILQ_HEAD(device_list, device) device_list_t; 62f9f848faSopenharmony_ci 63f9f848faSopenharmony_cistruct devclass { 64f9f848faSopenharmony_ci TAILQ_ENTRY(devclass) link; 65f9f848faSopenharmony_ci devclass_t parent; /* parent in devclass hierarchy */ 66f9f848faSopenharmony_ci driver_list_t drivers; /* bus devclasses store drivers for bus */ 67f9f848faSopenharmony_ci char *name; 68f9f848faSopenharmony_ci device_t *devices; /* array of devices indexed by unit */ 69f9f848faSopenharmony_ci int maxunit; /* size of devices array */ 70f9f848faSopenharmony_ci int flags; 71f9f848faSopenharmony_ci#define DC_HAS_CHILDREN 1 72f9f848faSopenharmony_ci}; 73f9f848faSopenharmony_ci 74f9f848faSopenharmony_ci/** 75f9f848faSopenharmony_ci * @brief Implementation of device. 76f9f848faSopenharmony_ci */ 77f9f848faSopenharmony_cistruct device { 78f9f848faSopenharmony_ci /* 79f9f848faSopenharmony_ci * A device is a kernel object. The first field must be the 80f9f848faSopenharmony_ci * current ops table for the object. 81f9f848faSopenharmony_ci */ 82f9f848faSopenharmony_ci KOBJ_FIELDS; 83f9f848faSopenharmony_ci 84f9f848faSopenharmony_ci /* 85f9f848faSopenharmony_ci * Device hierarchy. 86f9f848faSopenharmony_ci */ 87f9f848faSopenharmony_ci TAILQ_ENTRY(device) link; /**< list of devices in parent */ 88f9f848faSopenharmony_ci TAILQ_ENTRY(device) devlink; /**< global device list membership */ 89f9f848faSopenharmony_ci device_t parent; /**< parent of this device */ 90f9f848faSopenharmony_ci device_list_t children; /**< list of child devices */ 91f9f848faSopenharmony_ci 92f9f848faSopenharmony_ci /* 93f9f848faSopenharmony_ci * Details of this device. 94f9f848faSopenharmony_ci */ 95f9f848faSopenharmony_ci driver_t *driver; /**< current driver */ 96f9f848faSopenharmony_ci devclass_t devclass; /**< current device class */ 97f9f848faSopenharmony_ci int unit; /**< current unit number */ 98f9f848faSopenharmony_ci char* nameunit; /**< name+unit e.g. foodev0 */ 99f9f848faSopenharmony_ci char* desc; /**< driver specific description */ 100f9f848faSopenharmony_ci int busy; /**< count of calls to device_busy() */ 101f9f848faSopenharmony_ci device_state_t state; /**< current device state */ 102f9f848faSopenharmony_ci uint32_t devflags; /**< api level flags for device_get_flags() */ 103f9f848faSopenharmony_ci u_int flags; /**< internal device flags */ 104f9f848faSopenharmony_ci u_int order; /**< order from device_add_child_ordered() */ 105f9f848faSopenharmony_ci void *ivars; /**< instance variables */ 106f9f848faSopenharmony_ci void *softc; /**< current driver's variables */ 107f9f848faSopenharmony_ci}; 108f9f848faSopenharmony_ci 109f9f848faSopenharmony_cistatic MALLOC_DEFINE(M_BUS, "bus", "Bus data structures"); 110f9f848faSopenharmony_ci 111f9f848faSopenharmony_ci#ifdef BUS_DEBUG 112f9f848faSopenharmony_cistatic int bus_debug = 1; 113f9f848faSopenharmony_ci 114f9f848faSopenharmony_ci#define PDEBUG(a) if (bus_debug) {PRINTK("%s:%d: ", __func__, __LINE__), PRINTK a; PRINTK("\n");} 115f9f848faSopenharmony_ci#define DEVICENAME(d) ((d)? device_get_name(d): "no device") 116f9f848faSopenharmony_ci#define DRIVERNAME(d) ((d)? d->name : "no driver") 117f9f848faSopenharmony_ci#define DEVCLANAME(d) ((d)? d->name : "no devclass") 118f9f848faSopenharmony_ci 119f9f848faSopenharmony_ci/** 120f9f848faSopenharmony_ci * Produce the indenting, indent*2 spaces plus a '.' ahead of that to 121f9f848faSopenharmony_ci * prevent syslog from deleting initial spaces 122f9f848faSopenharmony_ci */ 123f9f848faSopenharmony_ci#define indentprintf(p) do { int iJ; PRINTK("."); for (iJ=0; iJ<indent; iJ++) PRINTK(" "); PRINTK p ; } while (0) 124f9f848faSopenharmony_ci 125f9f848faSopenharmony_cistatic void print_device_short(device_t dev, int indent); 126f9f848faSopenharmony_cistatic void print_device(device_t dev, int indent); 127f9f848faSopenharmony_civoid print_device_tree_short(device_t dev, int indent); 128f9f848faSopenharmony_civoid print_device_tree(device_t dev, int indent); 129f9f848faSopenharmony_cistatic void print_driver_short(driver_t *driver, int indent); 130f9f848faSopenharmony_cistatic void print_driver(driver_t *driver, int indent); 131f9f848faSopenharmony_cistatic void print_driver_list(driver_list_t drivers, int indent); 132f9f848faSopenharmony_cistatic void print_devclass_short(devclass_t dc, int indent); 133f9f848faSopenharmony_cistatic void print_devclass(devclass_t dc, int indent); 134f9f848faSopenharmony_civoid print_devclass_list_short(void); 135f9f848faSopenharmony_civoid print_devclass_list(void); 136f9f848faSopenharmony_ci 137f9f848faSopenharmony_ci#else 138f9f848faSopenharmony_ci/* Make the compiler ignore the function calls */ 139f9f848faSopenharmony_ci#define PDEBUG(a) /* nop */ 140f9f848faSopenharmony_ci#define DEVICENAME(d) /* nop */ 141f9f848faSopenharmony_ci#define DRIVERNAME(d) /* nop */ 142f9f848faSopenharmony_ci#define DEVCLANAME(d) /* nop */ 143f9f848faSopenharmony_ci 144f9f848faSopenharmony_ci#define print_device_short(d,i) /* nop */ 145f9f848faSopenharmony_ci#define print_device(d,i) /* nop */ 146f9f848faSopenharmony_ci#define print_device_tree_short(d,i) /* nop */ 147f9f848faSopenharmony_ci#define print_device_tree(d,i) /* nop */ 148f9f848faSopenharmony_ci#define print_driver_short(d,i) /* nop */ 149f9f848faSopenharmony_ci#define print_driver(d,i) /* nop */ 150f9f848faSopenharmony_ci#define print_driver_list(d,i) /* nop */ 151f9f848faSopenharmony_ci#define print_devclass_short(d,i) /* nop */ 152f9f848faSopenharmony_ci#define print_devclass(d,i) /* nop */ 153f9f848faSopenharmony_ci#define print_devclass_list_short() /* nop */ 154f9f848faSopenharmony_ci#define print_devclass_list() /* nop */ 155f9f848faSopenharmony_ci#endif 156f9f848faSopenharmony_ci 157f9f848faSopenharmony_cistatic TAILQ_HEAD(,device) bus_data_devices; 158f9f848faSopenharmony_cistatic int bus_data_generation = 1; 159f9f848faSopenharmony_ci 160f9f848faSopenharmony_cistatic kobj_method_t null_methods[] = { 161f9f848faSopenharmony_ci KOBJMETHOD_END 162f9f848faSopenharmony_ci}; 163f9f848faSopenharmony_ci 164f9f848faSopenharmony_ciDEFINE_CLASS(null, null_methods, 0); 165f9f848faSopenharmony_ci 166f9f848faSopenharmony_ci/* 167f9f848faSopenharmony_ci * Bus pass implementation 168f9f848faSopenharmony_ci */ 169f9f848faSopenharmony_ci 170f9f848faSopenharmony_cistatic driver_list_t passes = TAILQ_HEAD_INITIALIZER(passes); 171f9f848faSopenharmony_ciint bus_current_pass = BUS_PASS_ROOT; 172f9f848faSopenharmony_ci 173f9f848faSopenharmony_ci/** 174f9f848faSopenharmony_ci * @brief Return the name of the device's devclass or @c NULL if there 175f9f848faSopenharmony_ci * is none. 176f9f848faSopenharmony_ci */ 177f9f848faSopenharmony_ciconst char * 178f9f848faSopenharmony_cidevice_get_name(device_t dev) 179f9f848faSopenharmony_ci{ 180f9f848faSopenharmony_ci if (dev != NULL && dev->devclass) 181f9f848faSopenharmony_ci return (devclass_get_name(dev->devclass)); 182f9f848faSopenharmony_ci return (NULL); 183f9f848faSopenharmony_ci} 184f9f848faSopenharmony_ci 185f9f848faSopenharmony_ci/** 186f9f848faSopenharmony_ci * @internal 187f9f848faSopenharmony_ci * @brief Register the pass level of a new driver attachment 188f9f848faSopenharmony_ci * 189f9f848faSopenharmony_ci * Register a new driver attachment's pass level. If no driver 190f9f848faSopenharmony_ci * attachment with the same pass level has been added, then @p new 191f9f848faSopenharmony_ci * will be added to the global passes list. 192f9f848faSopenharmony_ci * 193f9f848faSopenharmony_ci * @param new the new driver attachment 194f9f848faSopenharmony_ci */ 195f9f848faSopenharmony_cistatic void 196f9f848faSopenharmony_cidriver_register_pass(struct driverlink *new) 197f9f848faSopenharmony_ci{ 198f9f848faSopenharmony_ci struct driverlink *dl = NULL; 199f9f848faSopenharmony_ci 200f9f848faSopenharmony_ci /* We only consider pass numbers during boot. */ 201f9f848faSopenharmony_ci if (bus_current_pass == BUS_PASS_DEFAULT) 202f9f848faSopenharmony_ci return; 203f9f848faSopenharmony_ci 204f9f848faSopenharmony_ci /* 205f9f848faSopenharmony_ci * Walk the passes list. If we already know about this pass 206f9f848faSopenharmony_ci * then there is nothing to do. If we don't, then insert this 207f9f848faSopenharmony_ci * driver link into the list. 208f9f848faSopenharmony_ci */ 209f9f848faSopenharmony_ci TAILQ_FOREACH(dl, &passes, passlink) { 210f9f848faSopenharmony_ci if (dl->pass < new->pass) 211f9f848faSopenharmony_ci continue; 212f9f848faSopenharmony_ci if (dl->pass == new->pass) 213f9f848faSopenharmony_ci return; 214f9f848faSopenharmony_ci TAILQ_INSERT_BEFORE(dl, new, passlink); 215f9f848faSopenharmony_ci return; 216f9f848faSopenharmony_ci } 217f9f848faSopenharmony_ci TAILQ_INSERT_TAIL(&passes, new, passlink); 218f9f848faSopenharmony_ci} 219f9f848faSopenharmony_ci 220f9f848faSopenharmony_ci/** 221f9f848faSopenharmony_ci * @brief Raise the current bus pass 222f9f848faSopenharmony_ci * 223f9f848faSopenharmony_ci * Raise the current bus pass level to @p pass. Call the BUS_NEW_PASS() 224f9f848faSopenharmony_ci * method on the root bus to kick off a new device tree scan for each 225f9f848faSopenharmony_ci * new pass level that has at least one driver. 226f9f848faSopenharmony_ci */ 227f9f848faSopenharmony_civoid 228f9f848faSopenharmony_cibus_set_pass(int pass) 229f9f848faSopenharmony_ci{ 230f9f848faSopenharmony_ci struct driverlink *dl = NULL; 231f9f848faSopenharmony_ci 232f9f848faSopenharmony_ci if (bus_current_pass > pass) 233f9f848faSopenharmony_ci panic("Attempt to lower bus pass level"); 234f9f848faSopenharmony_ci 235f9f848faSopenharmony_ci TAILQ_FOREACH(dl, &passes, passlink) { 236f9f848faSopenharmony_ci /* Skip pass values below the current pass level. */ 237f9f848faSopenharmony_ci if (dl->pass <= bus_current_pass) 238f9f848faSopenharmony_ci continue; 239f9f848faSopenharmony_ci 240f9f848faSopenharmony_ci /* 241f9f848faSopenharmony_ci * Bail once we hit a driver with a pass level that is 242f9f848faSopenharmony_ci * too high. 243f9f848faSopenharmony_ci */ 244f9f848faSopenharmony_ci if (dl->pass > pass) 245f9f848faSopenharmony_ci break; 246f9f848faSopenharmony_ci 247f9f848faSopenharmony_ci /* 248f9f848faSopenharmony_ci * Raise the pass level to the next level and rescan 249f9f848faSopenharmony_ci * the tree. 250f9f848faSopenharmony_ci */ 251f9f848faSopenharmony_ci bus_current_pass = dl->pass; 252f9f848faSopenharmony_ci BUS_NEW_PASS(root_bus); 253f9f848faSopenharmony_ci } 254f9f848faSopenharmony_ci 255f9f848faSopenharmony_ci /* 256f9f848faSopenharmony_ci * If there isn't a driver registered for the requested pass, 257f9f848faSopenharmony_ci * then bus_current_pass might still be less than 'pass'. Set 258f9f848faSopenharmony_ci * it to 'pass' in that case. 259f9f848faSopenharmony_ci */ 260f9f848faSopenharmony_ci if (bus_current_pass < pass) 261f9f848faSopenharmony_ci bus_current_pass = pass; 262f9f848faSopenharmony_ci KASSERT(bus_current_pass == pass, ("Failed to update bus pass level")); 263f9f848faSopenharmony_ci} 264f9f848faSopenharmony_ci 265f9f848faSopenharmony_ci/* 266f9f848faSopenharmony_ci * Devclass implementation 267f9f848faSopenharmony_ci */ 268f9f848faSopenharmony_ci 269f9f848faSopenharmony_cistatic devclass_list_t devclasses = TAILQ_HEAD_INITIALIZER(devclasses); 270f9f848faSopenharmony_ci 271f9f848faSopenharmony_ci/** 272f9f848faSopenharmony_ci * @internal 273f9f848faSopenharmony_ci * @brief Find or create a device class 274f9f848faSopenharmony_ci * 275f9f848faSopenharmony_ci * If a device class with the name @p classname exists, return it, 276f9f848faSopenharmony_ci * otherwise if @p create is non-zero create and return a new device 277f9f848faSopenharmony_ci * class. 278f9f848faSopenharmony_ci * 279f9f848faSopenharmony_ci * If @p parentname is non-NULL, the parent of the devclass is set to 280f9f848faSopenharmony_ci * the devclass of that name. 281f9f848faSopenharmony_ci * 282f9f848faSopenharmony_ci * @param classname the devclass name to find or create 283f9f848faSopenharmony_ci * @param parentname the parent devclass name or @c NULL 284f9f848faSopenharmony_ci * @param create non-zero to create a devclass 285f9f848faSopenharmony_ci */ 286f9f848faSopenharmony_cistatic devclass_t 287f9f848faSopenharmony_cidevclass_find_internal(const char *classname, const char *parentname, 288f9f848faSopenharmony_ci int create) 289f9f848faSopenharmony_ci{ 290f9f848faSopenharmony_ci devclass_t dc; 291f9f848faSopenharmony_ci 292f9f848faSopenharmony_ci PDEBUG(("looking for %s", classname)); 293f9f848faSopenharmony_ci if (!classname) 294f9f848faSopenharmony_ci return (NULL); 295f9f848faSopenharmony_ci 296f9f848faSopenharmony_ci TAILQ_FOREACH(dc, &devclasses, link) { 297f9f848faSopenharmony_ci if (!strcmp(dc->name, classname)) 298f9f848faSopenharmony_ci break; 299f9f848faSopenharmony_ci } 300f9f848faSopenharmony_ci 301f9f848faSopenharmony_ci if (create && !dc) { 302f9f848faSopenharmony_ci dc = bsd_malloc(sizeof(struct devclass) + strlen(classname) + 1, 303f9f848faSopenharmony_ci M_BUS, M_NOWAIT | M_ZERO); 304f9f848faSopenharmony_ci if (!dc) 305f9f848faSopenharmony_ci return (NULL); 306f9f848faSopenharmony_ci dc->parent = NULL; 307f9f848faSopenharmony_ci dc->name = (char*) (dc + 1); 308f9f848faSopenharmony_ci if (strcpy_s(dc->name, strlen(classname) + 1, classname) != EOK) { 309f9f848faSopenharmony_ci bsd_free(dc, M_BUS); 310f9f848faSopenharmony_ci return (NULL); 311f9f848faSopenharmony_ci } 312f9f848faSopenharmony_ci TAILQ_INIT(&dc->drivers); 313f9f848faSopenharmony_ci TAILQ_INSERT_TAIL(&devclasses, dc, link); 314f9f848faSopenharmony_ci 315f9f848faSopenharmony_ci PDEBUG(("create dc %p, %s", dc, classname)); 316f9f848faSopenharmony_ci bus_data_generation_update(); 317f9f848faSopenharmony_ci } 318f9f848faSopenharmony_ci 319f9f848faSopenharmony_ci /* 320f9f848faSopenharmony_ci * If a parent class is specified, then set that as our parent so 321f9f848faSopenharmony_ci * that this devclass will support drivers for the parent class as 322f9f848faSopenharmony_ci * well. If the parent class has the same name don't do this though 323f9f848faSopenharmony_ci * as it creates a cycle that can trigger an infinite loop in 324f9f848faSopenharmony_ci * device_probe_child() if a device exists for which there is no 325f9f848faSopenharmony_ci * suitable driver. 326f9f848faSopenharmony_ci */ 327f9f848faSopenharmony_ci if (parentname && dc && !dc->parent && 328f9f848faSopenharmony_ci strcmp(classname, parentname) != 0) { 329f9f848faSopenharmony_ci dc->parent = devclass_find_internal(parentname, NULL, TRUE); 330f9f848faSopenharmony_ci if (dc->parent == NULL) { 331f9f848faSopenharmony_ci return (NULL); 332f9f848faSopenharmony_ci } 333f9f848faSopenharmony_ci dc->parent->flags = (unsigned int)dc->parent->flags | DC_HAS_CHILDREN; 334f9f848faSopenharmony_ci } 335f9f848faSopenharmony_ci 336f9f848faSopenharmony_ci PDEBUG(("found dc %p, %s", dc, classname)); 337f9f848faSopenharmony_ci return (dc); 338f9f848faSopenharmony_ci} 339f9f848faSopenharmony_ci 340f9f848faSopenharmony_ci/** 341f9f848faSopenharmony_ci * @brief Create a device class 342f9f848faSopenharmony_ci * 343f9f848faSopenharmony_ci * If a device class with the name @p classname exists, return it, 344f9f848faSopenharmony_ci * otherwise create and return a new device class. 345f9f848faSopenharmony_ci * 346f9f848faSopenharmony_ci * @param classname the devclass name to find or create 347f9f848faSopenharmony_ci */ 348f9f848faSopenharmony_cidevclass_t 349f9f848faSopenharmony_cidevclass_create(const char *classname) 350f9f848faSopenharmony_ci{ 351f9f848faSopenharmony_ci return (devclass_find_internal(classname, NULL, TRUE)); 352f9f848faSopenharmony_ci} 353f9f848faSopenharmony_ci 354f9f848faSopenharmony_ci/** 355f9f848faSopenharmony_ci * @brief Find a device class 356f9f848faSopenharmony_ci * 357f9f848faSopenharmony_ci * If a device class with the name @p classname exists, return it, 358f9f848faSopenharmony_ci * otherwise return @c NULL. 359f9f848faSopenharmony_ci * 360f9f848faSopenharmony_ci * @param classname the devclass name to find 361f9f848faSopenharmony_ci */ 362f9f848faSopenharmony_cidevclass_t 363f9f848faSopenharmony_cidevclass_find(const char *classname) 364f9f848faSopenharmony_ci{ 365f9f848faSopenharmony_ci return (devclass_find_internal(classname, NULL, FALSE)); 366f9f848faSopenharmony_ci} 367f9f848faSopenharmony_ci 368f9f848faSopenharmony_ci/** 369f9f848faSopenharmony_ci * @brief Register that a device driver has been added to a devclass 370f9f848faSopenharmony_ci * 371f9f848faSopenharmony_ci * Register that a device driver has been added to a devclass. This 372f9f848faSopenharmony_ci * is called by devclass_add_driver to accomplish the recursive 373f9f848faSopenharmony_ci * notification of all the children classes of dc, as well as dc. 374f9f848faSopenharmony_ci * Each layer will have BUS_DRIVER_ADDED() called for all instances of 375f9f848faSopenharmony_ci * the devclass. 376f9f848faSopenharmony_ci * 377f9f848faSopenharmony_ci * We do a full search here of the devclass list at each iteration 378f9f848faSopenharmony_ci * level to save storing children-lists in the devclass structure. If 379f9f848faSopenharmony_ci * we ever move beyond a few dozen devices doing this, we may need to 380f9f848faSopenharmony_ci * reevaluate... 381f9f848faSopenharmony_ci * 382f9f848faSopenharmony_ci * @param dc the devclass to edit 383f9f848faSopenharmony_ci * @param driver the driver that was just added 384f9f848faSopenharmony_ci */ 385f9f848faSopenharmony_cistatic void 386f9f848faSopenharmony_cidevclass_driver_added(devclass_t dc, driver_t *driver) 387f9f848faSopenharmony_ci{ 388f9f848faSopenharmony_ci devclass_t parent; 389f9f848faSopenharmony_ci int i; 390f9f848faSopenharmony_ci 391f9f848faSopenharmony_ci /* 392f9f848faSopenharmony_ci * Call BUS_DRIVER_ADDED for any existing busses in this class. 393f9f848faSopenharmony_ci */ 394f9f848faSopenharmony_ci for (i = 0; i < dc->maxunit; i++) 395f9f848faSopenharmony_ci if (dc->devices[i] && device_is_attached(dc->devices[i])) 396f9f848faSopenharmony_ci BUS_DRIVER_ADDED(dc->devices[i], driver); 397f9f848faSopenharmony_ci 398f9f848faSopenharmony_ci /* 399f9f848faSopenharmony_ci * Walk through the children classes. Since we only keep a 400f9f848faSopenharmony_ci * single parent pointer around, we walk the entire list of 401f9f848faSopenharmony_ci * devclasses looking for children. We set the 402f9f848faSopenharmony_ci * DC_HAS_CHILDREN flag when a child devclass is created on 403f9f848faSopenharmony_ci * the parent, so we only walk the list for those devclasses 404f9f848faSopenharmony_ci * that have children. 405f9f848faSopenharmony_ci */ 406f9f848faSopenharmony_ci if (!((unsigned int)dc->flags & DC_HAS_CHILDREN)) 407f9f848faSopenharmony_ci return; 408f9f848faSopenharmony_ci parent = dc; 409f9f848faSopenharmony_ci TAILQ_FOREACH(dc, &devclasses, link) { 410f9f848faSopenharmony_ci if (dc->parent == parent) 411f9f848faSopenharmony_ci devclass_driver_added(dc, driver); 412f9f848faSopenharmony_ci } 413f9f848faSopenharmony_ci} 414f9f848faSopenharmony_ci 415f9f848faSopenharmony_ci/** 416f9f848faSopenharmony_ci * @brief Add a device driver to a device class 417f9f848faSopenharmony_ci * 418f9f848faSopenharmony_ci * Add a device driver to a devclass. This is normally called 419f9f848faSopenharmony_ci * automatically by DRIVER_MODULE(). The BUS_DRIVER_ADDED() method of 420f9f848faSopenharmony_ci * all devices in the devclass will be called to allow them to attempt 421f9f848faSopenharmony_ci * to re-probe any unmatched children. 422f9f848faSopenharmony_ci * 423f9f848faSopenharmony_ci * @param dc the devclass to edit 424f9f848faSopenharmony_ci * @param driver the driver to register 425f9f848faSopenharmony_ci */ 426f9f848faSopenharmony_ciint 427f9f848faSopenharmony_cidevclass_add_driver(devclass_t dc, driver_t *driver, int pass, devclass_t *dcp) 428f9f848faSopenharmony_ci{ 429f9f848faSopenharmony_ci driverlink_t dl = NULL; 430f9f848faSopenharmony_ci const char *parentname = NULL; 431f9f848faSopenharmony_ci 432f9f848faSopenharmony_ci PDEBUG(("%s +", DRIVERNAME(driver))); 433f9f848faSopenharmony_ci 434f9f848faSopenharmony_ci /* Don't allow invalid pass values. */ 435f9f848faSopenharmony_ci if (pass <= BUS_PASS_ROOT) 436f9f848faSopenharmony_ci return (EINVAL); 437f9f848faSopenharmony_ci 438f9f848faSopenharmony_ci dl = bsd_malloc(sizeof *dl, M_BUS, M_NOWAIT|M_ZERO); 439f9f848faSopenharmony_ci if (!dl) 440f9f848faSopenharmony_ci return (ENOMEM); 441f9f848faSopenharmony_ci 442f9f848faSopenharmony_ci /* 443f9f848faSopenharmony_ci * Compile the driver's methods. Also increase the reference count 444f9f848faSopenharmony_ci * so that the class doesn't get freed when the last instance 445f9f848faSopenharmony_ci * goes. This means we can safely use static methods and avoids a 446f9f848faSopenharmony_ci * double-free in devclass_delete_driver. 447f9f848faSopenharmony_ci */ 448f9f848faSopenharmony_ci kobj_class_compile((kobj_class_t) driver); 449f9f848faSopenharmony_ci 450f9f848faSopenharmony_ci /* 451f9f848faSopenharmony_ci * If the driver has any base classes, make the 452f9f848faSopenharmony_ci * devclass inherit from the devclass of the driver's 453f9f848faSopenharmony_ci * first base class. This will allow the system to 454f9f848faSopenharmony_ci * search for drivers in both devclasses for children 455f9f848faSopenharmony_ci * of a device using this driver. 456f9f848faSopenharmony_ci */ 457f9f848faSopenharmony_ci if (driver->baseclasses) 458f9f848faSopenharmony_ci parentname = driver->baseclasses[0]->name; 459f9f848faSopenharmony_ci else 460f9f848faSopenharmony_ci parentname = NULL; 461f9f848faSopenharmony_ci *dcp = devclass_find_internal(driver->name, parentname, TRUE); 462f9f848faSopenharmony_ci 463f9f848faSopenharmony_ci dl->driver = driver; 464f9f848faSopenharmony_ci TAILQ_INSERT_TAIL(&dc->drivers, dl, link); 465f9f848faSopenharmony_ci driver->refs++; /* XXX: kobj_mtx */ 466f9f848faSopenharmony_ci dl->pass = pass; 467f9f848faSopenharmony_ci driver_register_pass(dl); 468f9f848faSopenharmony_ci 469f9f848faSopenharmony_ci devclass_driver_added(dc, driver); 470f9f848faSopenharmony_ci bus_data_generation_update(); 471f9f848faSopenharmony_ci PDEBUG(("%s -", DRIVERNAME(driver))); 472f9f848faSopenharmony_ci return (0); 473f9f848faSopenharmony_ci} 474f9f848faSopenharmony_ci 475f9f848faSopenharmony_ci/** 476f9f848faSopenharmony_ci * @brief Register that a device driver has been deleted from a devclass 477f9f848faSopenharmony_ci * 478f9f848faSopenharmony_ci * Register that a device driver has been removed from a devclass. 479f9f848faSopenharmony_ci * This is called by devclass_delete_driver to accomplish the 480f9f848faSopenharmony_ci * recursive notification of all the children classes of busclass, as 481f9f848faSopenharmony_ci * well as busclass. Each layer will attempt to detach the driver 482f9f848faSopenharmony_ci * from any devices that are children of the bus's devclass. The function 483f9f848faSopenharmony_ci * will return an error if a device fails to detach. 484f9f848faSopenharmony_ci * 485f9f848faSopenharmony_ci * We do a full search here of the devclass list at each iteration 486f9f848faSopenharmony_ci * level to save storing children-lists in the devclass structure. If 487f9f848faSopenharmony_ci * we ever move beyond a few dozen devices doing this, we may need to 488f9f848faSopenharmony_ci * reevaluate... 489f9f848faSopenharmony_ci * 490f9f848faSopenharmony_ci * @param busclass the devclass of the parent bus 491f9f848faSopenharmony_ci * @param dc the devclass of the driver being deleted 492f9f848faSopenharmony_ci * @param driver the driver being deleted 493f9f848faSopenharmony_ci */ 494f9f848faSopenharmony_cistatic int 495f9f848faSopenharmony_cidevclass_driver_deleted(devclass_t busclass, devclass_t dc, driver_t *driver) 496f9f848faSopenharmony_ci{ 497f9f848faSopenharmony_ci devclass_t parent; 498f9f848faSopenharmony_ci device_t dev; 499f9f848faSopenharmony_ci int error, i; 500f9f848faSopenharmony_ci 501f9f848faSopenharmony_ci /* 502f9f848faSopenharmony_ci * Disassociate from any devices. We iterate through all the 503f9f848faSopenharmony_ci * devices in the devclass of the driver and detach any which are 504f9f848faSopenharmony_ci * using the driver and which have a parent in the devclass which 505f9f848faSopenharmony_ci * we are deleting from. 506f9f848faSopenharmony_ci * 507f9f848faSopenharmony_ci * Note that since a driver can be in multiple devclasses, we 508f9f848faSopenharmony_ci * should not detach devices which are not children of devices in 509f9f848faSopenharmony_ci * the affected devclass. 510f9f848faSopenharmony_ci */ 511f9f848faSopenharmony_ci for (i = 0; i < dc->maxunit; i++) { 512f9f848faSopenharmony_ci if (dc->devices[i]) { 513f9f848faSopenharmony_ci dev = dc->devices[i]; 514f9f848faSopenharmony_ci if (dev->driver == driver && dev->parent && 515f9f848faSopenharmony_ci dev->parent->devclass == busclass) { 516f9f848faSopenharmony_ci if ((error = device_detach(dev)) != 0) 517f9f848faSopenharmony_ci return (error); 518f9f848faSopenharmony_ci BUS_PROBE_NOMATCH(dev->parent, dev); 519f9f848faSopenharmony_ci // devnomatch(dev); 520f9f848faSopenharmony_ci dev->flags |= DF_DONENOMATCH; 521f9f848faSopenharmony_ci } 522f9f848faSopenharmony_ci } 523f9f848faSopenharmony_ci } 524f9f848faSopenharmony_ci 525f9f848faSopenharmony_ci /* 526f9f848faSopenharmony_ci * Walk through the children classes. Since we only keep a 527f9f848faSopenharmony_ci * single parent pointer around, we walk the entire list of 528f9f848faSopenharmony_ci * devclasses looking for children. We set the 529f9f848faSopenharmony_ci * DC_HAS_CHILDREN flag when a child devclass is created on 530f9f848faSopenharmony_ci * the parent, so we only walk the list for those devclasses 531f9f848faSopenharmony_ci * that have children. 532f9f848faSopenharmony_ci */ 533f9f848faSopenharmony_ci if (!((unsigned int)busclass->flags & DC_HAS_CHILDREN)) 534f9f848faSopenharmony_ci return (0); 535f9f848faSopenharmony_ci parent = busclass; 536f9f848faSopenharmony_ci TAILQ_FOREACH(busclass, &devclasses, link) { 537f9f848faSopenharmony_ci if (busclass->parent == parent) { 538f9f848faSopenharmony_ci error = devclass_driver_deleted(busclass, dc, driver); 539f9f848faSopenharmony_ci if (error) 540f9f848faSopenharmony_ci return (error); 541f9f848faSopenharmony_ci } 542f9f848faSopenharmony_ci } 543f9f848faSopenharmony_ci return (0); 544f9f848faSopenharmony_ci} 545f9f848faSopenharmony_ci 546f9f848faSopenharmony_ci/** 547f9f848faSopenharmony_ci * @brief Delete a device driver from a device class 548f9f848faSopenharmony_ci * 549f9f848faSopenharmony_ci * Delete a device driver from a devclass. This is normally called 550f9f848faSopenharmony_ci * automatically by DRIVER_MODULE(). 551f9f848faSopenharmony_ci * 552f9f848faSopenharmony_ci * If the driver is currently attached to any devices, 553f9f848faSopenharmony_ci * devclass_delete_driver() will first attempt to detach from each 554f9f848faSopenharmony_ci * device. If one of the detach calls fails, the driver will not be 555f9f848faSopenharmony_ci * deleted. 556f9f848faSopenharmony_ci * 557f9f848faSopenharmony_ci * @param dc the devclass to edit 558f9f848faSopenharmony_ci * @param driver the driver to unregister 559f9f848faSopenharmony_ci */ 560f9f848faSopenharmony_ciint 561f9f848faSopenharmony_cidevclass_delete_driver(devclass_t busclass, driver_t *driver) 562f9f848faSopenharmony_ci{ 563f9f848faSopenharmony_ci devclass_t dc = devclass_find(driver->name); 564f9f848faSopenharmony_ci driverlink_t dl = NULL; 565f9f848faSopenharmony_ci int error; 566f9f848faSopenharmony_ci 567f9f848faSopenharmony_ci PDEBUG(("%s from devclass %s", driver->name, DEVCLANAME(busclass))); 568f9f848faSopenharmony_ci 569f9f848faSopenharmony_ci if (!dc) 570f9f848faSopenharmony_ci return (0); 571f9f848faSopenharmony_ci 572f9f848faSopenharmony_ci /* 573f9f848faSopenharmony_ci * Find the link structure in the bus' list of drivers. 574f9f848faSopenharmony_ci */ 575f9f848faSopenharmony_ci TAILQ_FOREACH(dl, &busclass->drivers, link) { 576f9f848faSopenharmony_ci if (dl->driver == driver) 577f9f848faSopenharmony_ci break; 578f9f848faSopenharmony_ci } 579f9f848faSopenharmony_ci 580f9f848faSopenharmony_ci if (!dl) { 581f9f848faSopenharmony_ci PDEBUG(("%s not found in %s list", driver->name, 582f9f848faSopenharmony_ci busclass->name)); 583f9f848faSopenharmony_ci return (ENOENT); 584f9f848faSopenharmony_ci } 585f9f848faSopenharmony_ci 586f9f848faSopenharmony_ci error = devclass_driver_deleted(busclass, dc, driver); 587f9f848faSopenharmony_ci if (error != 0) 588f9f848faSopenharmony_ci return (error); 589f9f848faSopenharmony_ci 590f9f848faSopenharmony_ci TAILQ_REMOVE(&busclass->drivers, dl, link); 591f9f848faSopenharmony_ci bsd_free(dl, M_BUS); 592f9f848faSopenharmony_ci 593f9f848faSopenharmony_ci /* XXX: kobj_mtx */ 594f9f848faSopenharmony_ci driver->refs--; 595f9f848faSopenharmony_ci if (driver->refs == 0) 596f9f848faSopenharmony_ci kobj_class_free((kobj_class_t) driver); 597f9f848faSopenharmony_ci 598f9f848faSopenharmony_ci bus_data_generation_update(); 599f9f848faSopenharmony_ci return (0); 600f9f848faSopenharmony_ci} 601f9f848faSopenharmony_ci 602f9f848faSopenharmony_ci/** 603f9f848faSopenharmony_ci * @brief Quiesces a set of device drivers from a device class 604f9f848faSopenharmony_ci * 605f9f848faSopenharmony_ci * Quiesce a device driver from a devclass. This is normally called 606f9f848faSopenharmony_ci * automatically by DRIVER_MODULE(). 607f9f848faSopenharmony_ci * 608f9f848faSopenharmony_ci * If the driver is currently attached to any devices, 609f9f848faSopenharmony_ci * devclass_quiesece_driver() will first attempt to quiesce each 610f9f848faSopenharmony_ci * device. 611f9f848faSopenharmony_ci * 612f9f848faSopenharmony_ci * @param dc the devclass to edit 613f9f848faSopenharmony_ci * @param driver the driver to unregister 614f9f848faSopenharmony_ci */ 615f9f848faSopenharmony_cistatic int 616f9f848faSopenharmony_cidevclass_quiesce_driver(devclass_t busclass, driver_t *driver) 617f9f848faSopenharmony_ci{ 618f9f848faSopenharmony_ci devclass_t dc = devclass_find(driver->name); 619f9f848faSopenharmony_ci driverlink_t dl = NULL; 620f9f848faSopenharmony_ci device_t dev; 621f9f848faSopenharmony_ci int i; 622f9f848faSopenharmony_ci int error; 623f9f848faSopenharmony_ci 624f9f848faSopenharmony_ci PDEBUG(("%s from devclass %s", driver->name, DEVCLANAME(busclass))); 625f9f848faSopenharmony_ci 626f9f848faSopenharmony_ci if (!dc) 627f9f848faSopenharmony_ci return (0); 628f9f848faSopenharmony_ci 629f9f848faSopenharmony_ci /* 630f9f848faSopenharmony_ci * Find the link structure in the bus' list of drivers. 631f9f848faSopenharmony_ci */ 632f9f848faSopenharmony_ci TAILQ_FOREACH(dl, &busclass->drivers, link) { 633f9f848faSopenharmony_ci if (dl->driver == driver) 634f9f848faSopenharmony_ci break; 635f9f848faSopenharmony_ci } 636f9f848faSopenharmony_ci 637f9f848faSopenharmony_ci if (!dl) { 638f9f848faSopenharmony_ci PDEBUG(("%s not found in %s list", driver->name, 639f9f848faSopenharmony_ci busclass->name)); 640f9f848faSopenharmony_ci return (ENOENT); 641f9f848faSopenharmony_ci } 642f9f848faSopenharmony_ci 643f9f848faSopenharmony_ci /* 644f9f848faSopenharmony_ci * Quiesce all devices. We iterate through all the devices in 645f9f848faSopenharmony_ci * the devclass of the driver and quiesce any which are using 646f9f848faSopenharmony_ci * the driver and which have a parent in the devclass which we 647f9f848faSopenharmony_ci * are quiescing. 648f9f848faSopenharmony_ci * 649f9f848faSopenharmony_ci * Note that since a driver can be in multiple devclasses, we 650f9f848faSopenharmony_ci * should not quiesce devices which are not children of 651f9f848faSopenharmony_ci * devices in the affected devclass. 652f9f848faSopenharmony_ci */ 653f9f848faSopenharmony_ci for (i = 0; i < dc->maxunit; i++) { 654f9f848faSopenharmony_ci if (dc->devices[i]) { 655f9f848faSopenharmony_ci dev = dc->devices[i]; 656f9f848faSopenharmony_ci if (dev->driver == driver && dev->parent && 657f9f848faSopenharmony_ci dev->parent->devclass == busclass) { 658f9f848faSopenharmony_ci if ((error = device_quiesce(dev)) != 0) 659f9f848faSopenharmony_ci return (error); 660f9f848faSopenharmony_ci } 661f9f848faSopenharmony_ci } 662f9f848faSopenharmony_ci } 663f9f848faSopenharmony_ci 664f9f848faSopenharmony_ci return (0); 665f9f848faSopenharmony_ci} 666f9f848faSopenharmony_ci 667f9f848faSopenharmony_ci/** 668f9f848faSopenharmony_ci * @internal 669f9f848faSopenharmony_ci */ 670f9f848faSopenharmony_cistatic driverlink_t 671f9f848faSopenharmony_cidevclass_find_driver_internal(devclass_t dc, const char *classname) 672f9f848faSopenharmony_ci{ 673f9f848faSopenharmony_ci driverlink_t dl = NULL; 674f9f848faSopenharmony_ci 675f9f848faSopenharmony_ci PDEBUG(("%s in devclass %s", classname, DEVCLANAME(dc))); 676f9f848faSopenharmony_ci 677f9f848faSopenharmony_ci TAILQ_FOREACH(dl, &dc->drivers, link) { 678f9f848faSopenharmony_ci if (!strcmp(dl->driver->name, classname)) 679f9f848faSopenharmony_ci return (dl); 680f9f848faSopenharmony_ci } 681f9f848faSopenharmony_ci 682f9f848faSopenharmony_ci PDEBUG(("not found")); 683f9f848faSopenharmony_ci return (NULL); 684f9f848faSopenharmony_ci} 685f9f848faSopenharmony_ci 686f9f848faSopenharmony_ci/** 687f9f848faSopenharmony_ci * @brief Return the name of the devclass 688f9f848faSopenharmony_ci */ 689f9f848faSopenharmony_ciconst char * 690f9f848faSopenharmony_cidevclass_get_name(devclass_t dc) 691f9f848faSopenharmony_ci{ 692f9f848faSopenharmony_ci return (dc->name); 693f9f848faSopenharmony_ci} 694f9f848faSopenharmony_ci 695f9f848faSopenharmony_ci/** 696f9f848faSopenharmony_ci * @brief Find a device given a unit number 697f9f848faSopenharmony_ci * 698f9f848faSopenharmony_ci * @param dc the devclass to search 699f9f848faSopenharmony_ci * @param unit the unit number to search for 700f9f848faSopenharmony_ci * 701f9f848faSopenharmony_ci * @returns the device with the given unit number or @c 702f9f848faSopenharmony_ci * NULL if there is no such device 703f9f848faSopenharmony_ci */ 704f9f848faSopenharmony_cidevice_t 705f9f848faSopenharmony_cidevclass_get_device(devclass_t dc, int unit) 706f9f848faSopenharmony_ci{ 707f9f848faSopenharmony_ci if (dc == NULL || unit < 0 || unit >= dc->maxunit) 708f9f848faSopenharmony_ci return (NULL); 709f9f848faSopenharmony_ci return (dc->devices[unit]); 710f9f848faSopenharmony_ci} 711f9f848faSopenharmony_ci 712f9f848faSopenharmony_ci/** 713f9f848faSopenharmony_ci * @brief Find the softc field of a device given a unit number 714f9f848faSopenharmony_ci * 715f9f848faSopenharmony_ci * @param dc the devclass to search 716f9f848faSopenharmony_ci * @param unit the unit number to search for 717f9f848faSopenharmony_ci * 718f9f848faSopenharmony_ci * @returns the softc field of the device with the given 719f9f848faSopenharmony_ci * unit number or @c NULL if there is no such 720f9f848faSopenharmony_ci * device 721f9f848faSopenharmony_ci */ 722f9f848faSopenharmony_civoid * 723f9f848faSopenharmony_cidevclass_get_softc(devclass_t dc, int unit) 724f9f848faSopenharmony_ci{ 725f9f848faSopenharmony_ci device_t dev; 726f9f848faSopenharmony_ci 727f9f848faSopenharmony_ci dev = devclass_get_device(dc, unit); 728f9f848faSopenharmony_ci if (!dev) 729f9f848faSopenharmony_ci return (NULL); 730f9f848faSopenharmony_ci 731f9f848faSopenharmony_ci return (device_get_softc(dev)); 732f9f848faSopenharmony_ci} 733f9f848faSopenharmony_ci 734f9f848faSopenharmony_ci/** 735f9f848faSopenharmony_ci * @brief Get a list of devices in the devclass 736f9f848faSopenharmony_ci * 737f9f848faSopenharmony_ci * An array containing a list of all the devices in the given devclass 738f9f848faSopenharmony_ci * is allocated and returned in @p *devlistp. The number of devices 739f9f848faSopenharmony_ci * in the array is returned in @p *devcountp. The caller should free 740f9f848faSopenharmony_ci * the array using @c free(p, M_TEMP), even if @p *devcountp is 0. 741f9f848faSopenharmony_ci * 742f9f848faSopenharmony_ci * @param dc the devclass to examine 743f9f848faSopenharmony_ci * @param devlistp points at location for array pointer return 744f9f848faSopenharmony_ci * value 745f9f848faSopenharmony_ci * @param devcountp points at location for array size return value 746f9f848faSopenharmony_ci * 747f9f848faSopenharmony_ci * @retval 0 success 748f9f848faSopenharmony_ci * @retval ENOMEM the array allocation failed 749f9f848faSopenharmony_ci */ 750f9f848faSopenharmony_ciint 751f9f848faSopenharmony_cidevclass_get_devices(devclass_t dc, device_t **devlistp, int *devcountp) 752f9f848faSopenharmony_ci{ 753f9f848faSopenharmony_ci int count, i; 754f9f848faSopenharmony_ci device_t *list; 755f9f848faSopenharmony_ci 756f9f848faSopenharmony_ci count = devclass_get_count(dc); 757f9f848faSopenharmony_ci list = bsd_malloc(count * sizeof(device_t), M_TEMP, M_NOWAIT|M_ZERO); 758f9f848faSopenharmony_ci if (!list) 759f9f848faSopenharmony_ci return (ENOMEM); 760f9f848faSopenharmony_ci 761f9f848faSopenharmony_ci count = 0; 762f9f848faSopenharmony_ci for (i = 0; i < dc->maxunit; i++) { 763f9f848faSopenharmony_ci if (dc->devices[i]) { 764f9f848faSopenharmony_ci list[count] = dc->devices[i]; 765f9f848faSopenharmony_ci count++; 766f9f848faSopenharmony_ci } 767f9f848faSopenharmony_ci } 768f9f848faSopenharmony_ci 769f9f848faSopenharmony_ci *devlistp = list; 770f9f848faSopenharmony_ci *devcountp = count; 771f9f848faSopenharmony_ci 772f9f848faSopenharmony_ci return (0); 773f9f848faSopenharmony_ci} 774f9f848faSopenharmony_ci 775f9f848faSopenharmony_ci/** 776f9f848faSopenharmony_ci * @brief Get a list of drivers in the devclass 777f9f848faSopenharmony_ci * 778f9f848faSopenharmony_ci * An array containing a list of pointers to all the drivers in the 779f9f848faSopenharmony_ci * given devclass is allocated and returned in @p *listp. The number 780f9f848faSopenharmony_ci * of drivers in the array is returned in @p *countp. The caller should 781f9f848faSopenharmony_ci * free the array using @c free(p, M_TEMP). 782f9f848faSopenharmony_ci * 783f9f848faSopenharmony_ci * @param dc the devclass to examine 784f9f848faSopenharmony_ci * @param listp gives location for array pointer return value 785f9f848faSopenharmony_ci * @param countp gives location for number of array elements 786f9f848faSopenharmony_ci * return value 787f9f848faSopenharmony_ci * 788f9f848faSopenharmony_ci * @retval 0 success 789f9f848faSopenharmony_ci * @retval ENOMEM the array allocation failed 790f9f848faSopenharmony_ci */ 791f9f848faSopenharmony_ciint 792f9f848faSopenharmony_cidevclass_get_drivers(devclass_t dc, driver_t ***listp, int *countp) 793f9f848faSopenharmony_ci{ 794f9f848faSopenharmony_ci driverlink_t dl = NULL; 795f9f848faSopenharmony_ci driver_t **list = NULL; 796f9f848faSopenharmony_ci int count; 797f9f848faSopenharmony_ci 798f9f848faSopenharmony_ci count = 0; 799f9f848faSopenharmony_ci TAILQ_FOREACH(dl, &dc->drivers, link) 800f9f848faSopenharmony_ci count++; 801f9f848faSopenharmony_ci list = bsd_malloc(count * sizeof(driver_t *), M_TEMP, M_NOWAIT); 802f9f848faSopenharmony_ci if (list == NULL) 803f9f848faSopenharmony_ci return (ENOMEM); 804f9f848faSopenharmony_ci 805f9f848faSopenharmony_ci count = 0; 806f9f848faSopenharmony_ci TAILQ_FOREACH(dl, &dc->drivers, link) { 807f9f848faSopenharmony_ci list[count] = dl->driver; 808f9f848faSopenharmony_ci count++; 809f9f848faSopenharmony_ci } 810f9f848faSopenharmony_ci *listp = list; 811f9f848faSopenharmony_ci *countp = count; 812f9f848faSopenharmony_ci 813f9f848faSopenharmony_ci return (0); 814f9f848faSopenharmony_ci} 815f9f848faSopenharmony_ci 816f9f848faSopenharmony_ci/** 817f9f848faSopenharmony_ci * @brief Get the number of devices in a devclass 818f9f848faSopenharmony_ci * 819f9f848faSopenharmony_ci * @param dc the devclass to examine 820f9f848faSopenharmony_ci */ 821f9f848faSopenharmony_ciint 822f9f848faSopenharmony_cidevclass_get_count(devclass_t dc) 823f9f848faSopenharmony_ci{ 824f9f848faSopenharmony_ci int count, i; 825f9f848faSopenharmony_ci 826f9f848faSopenharmony_ci count = 0; 827f9f848faSopenharmony_ci for (i = 0; i < dc->maxunit; i++) 828f9f848faSopenharmony_ci if (dc->devices[i]) 829f9f848faSopenharmony_ci count++; 830f9f848faSopenharmony_ci return (count); 831f9f848faSopenharmony_ci} 832f9f848faSopenharmony_ci 833f9f848faSopenharmony_ci/** 834f9f848faSopenharmony_ci * @brief Get the maximum unit number used in a devclass 835f9f848faSopenharmony_ci * 836f9f848faSopenharmony_ci * Note that this is one greater than the highest currently-allocated 837f9f848faSopenharmony_ci * unit. If a null devclass_t is passed in, -1 is returned to indicate 838f9f848faSopenharmony_ci * that not even the devclass has been allocated yet. 839f9f848faSopenharmony_ci * 840f9f848faSopenharmony_ci * @param dc the devclass to examine 841f9f848faSopenharmony_ci */ 842f9f848faSopenharmony_ciint 843f9f848faSopenharmony_cidevclass_get_maxunit(devclass_t dc) 844f9f848faSopenharmony_ci{ 845f9f848faSopenharmony_ci if (dc == NULL) 846f9f848faSopenharmony_ci return (-1); 847f9f848faSopenharmony_ci return (dc->maxunit); 848f9f848faSopenharmony_ci} 849f9f848faSopenharmony_ci 850f9f848faSopenharmony_ci/** 851f9f848faSopenharmony_ci * @brief Find a free unit number in a devclass 852f9f848faSopenharmony_ci * 853f9f848faSopenharmony_ci * This function searches for the first unused unit number greater 854f9f848faSopenharmony_ci * that or equal to @p unit. 855f9f848faSopenharmony_ci * 856f9f848faSopenharmony_ci * @param dc the devclass to examine 857f9f848faSopenharmony_ci * @param unit the first unit number to check 858f9f848faSopenharmony_ci */ 859f9f848faSopenharmony_ciint 860f9f848faSopenharmony_cidevclass_find_free_unit(devclass_t dc, int unit) 861f9f848faSopenharmony_ci{ 862f9f848faSopenharmony_ci if (dc == NULL) 863f9f848faSopenharmony_ci return (unit); 864f9f848faSopenharmony_ci while (unit < dc->maxunit && dc->devices[unit] != NULL) 865f9f848faSopenharmony_ci unit++; 866f9f848faSopenharmony_ci return (unit); 867f9f848faSopenharmony_ci} 868f9f848faSopenharmony_ci 869f9f848faSopenharmony_ci/** 870f9f848faSopenharmony_ci * @brief Set the parent of a devclass 871f9f848faSopenharmony_ci * 872f9f848faSopenharmony_ci * The parent class is normally initialised automatically by 873f9f848faSopenharmony_ci * DRIVER_MODULE(). 874f9f848faSopenharmony_ci * 875f9f848faSopenharmony_ci * @param dc the devclass to edit 876f9f848faSopenharmony_ci * @param pdc the new parent devclass 877f9f848faSopenharmony_ci */ 878f9f848faSopenharmony_civoid 879f9f848faSopenharmony_cidevclass_set_parent(devclass_t dc, devclass_t pdc) 880f9f848faSopenharmony_ci{ 881f9f848faSopenharmony_ci dc->parent = pdc; 882f9f848faSopenharmony_ci} 883f9f848faSopenharmony_ci 884f9f848faSopenharmony_ci/** 885f9f848faSopenharmony_ci * @brief Get the parent of a devclass 886f9f848faSopenharmony_ci * 887f9f848faSopenharmony_ci * @param dc the devclass to examine 888f9f848faSopenharmony_ci */ 889f9f848faSopenharmony_cidevclass_t 890f9f848faSopenharmony_cidevclass_get_parent(devclass_t dc) 891f9f848faSopenharmony_ci{ 892f9f848faSopenharmony_ci return (dc->parent); 893f9f848faSopenharmony_ci} 894f9f848faSopenharmony_ci 895f9f848faSopenharmony_ci/** 896f9f848faSopenharmony_ci * @internal 897f9f848faSopenharmony_ci * @brief Allocate a unit number 898f9f848faSopenharmony_ci * 899f9f848faSopenharmony_ci * On entry, @p *unitp is the desired unit number (or @c -1 if any 900f9f848faSopenharmony_ci * will do). The allocated unit number is returned in @p *unitp. 901f9f848faSopenharmony_ci 902f9f848faSopenharmony_ci * @param dc the devclass to allocate from 903f9f848faSopenharmony_ci * @param unitp points at the location for the allocated unit 904f9f848faSopenharmony_ci * number 905f9f848faSopenharmony_ci * 906f9f848faSopenharmony_ci * @retval 0 success 907f9f848faSopenharmony_ci * @retval EEXIST the requested unit number is already allocated 908f9f848faSopenharmony_ci * @retval ENOMEM memory allocation failure 909f9f848faSopenharmony_ci */ 910f9f848faSopenharmony_cistatic int 911f9f848faSopenharmony_cidevclass_alloc_unit(devclass_t dc, device_t dev, int *unitp) 912f9f848faSopenharmony_ci{ 913f9f848faSopenharmony_ci int unit = *unitp; 914f9f848faSopenharmony_ci 915f9f848faSopenharmony_ci PDEBUG(("unit %d in devclass %s", unit, DEVCLANAME(dc))); 916f9f848faSopenharmony_ci 917f9f848faSopenharmony_ci /* Ask the parent bus if it wants to wire this device. */ 918f9f848faSopenharmony_ci if (unit == -1) 919f9f848faSopenharmony_ci BUS_HINT_DEVICE_UNIT(device_get_parent(dev), dev, dc->name, &unit); 920f9f848faSopenharmony_ci 921f9f848faSopenharmony_ci /* If we were given a wired unit number, check for existing device */ 922f9f848faSopenharmony_ci /* XXX imp XXX */ 923f9f848faSopenharmony_ci if (unit != -1) { 924f9f848faSopenharmony_ci if (unit >= 0 && unit < dc->maxunit && dc->devices[unit] != NULL) { 925f9f848faSopenharmony_ci if (bootverbose) 926f9f848faSopenharmony_ci printf("%s: %s%d already exists; skipping it\n", dc->name, dc->name, *unitp); 927f9f848faSopenharmony_ci return (EEXIST); 928f9f848faSopenharmony_ci } 929f9f848faSopenharmony_ci } else { 930f9f848faSopenharmony_ci /* Unwired device, find the next available slot for it */ 931f9f848faSopenharmony_ci unit = 0; 932f9f848faSopenharmony_ci for (unit = 0;; unit++) { 933f9f848faSopenharmony_ci /* If this device slot is already in use, skip it. */ 934f9f848faSopenharmony_ci if (unit < dc->maxunit && dc->devices[unit] != NULL) 935f9f848faSopenharmony_ci continue; 936f9f848faSopenharmony_ci 937f9f848faSopenharmony_ci break; 938f9f848faSopenharmony_ci } 939f9f848faSopenharmony_ci } 940f9f848faSopenharmony_ci PDEBUG(("mid: unit %d in devclass %s", unit, DEVCLANAME(dc))); 941f9f848faSopenharmony_ci /* 942f9f848faSopenharmony_ci * We've selected a unit beyond the length of the table, so let's 943f9f848faSopenharmony_ci * extend the table to make room for all units up to and including 944f9f848faSopenharmony_ci * this one. 945f9f848faSopenharmony_ci */ 946f9f848faSopenharmony_ci if (unit >= dc->maxunit) { 947f9f848faSopenharmony_ci device_t *newlist, *oldlist; 948f9f848faSopenharmony_ci int newsize; 949f9f848faSopenharmony_ci 950f9f848faSopenharmony_ci oldlist = dc->devices; 951f9f848faSopenharmony_ci newsize = roundup((unit + 1), MINALLOCSIZE / sizeof(device_t)); 952f9f848faSopenharmony_ci newlist = bsd_malloc(sizeof(device_t) * newsize, M_BUS, M_NOWAIT); 953f9f848faSopenharmony_ci PDEBUG(("oldlist %p, newlist %p, newsize %d", oldlist, newlist, newsize)); 954f9f848faSopenharmony_ci if (!newlist) 955f9f848faSopenharmony_ci return (ENOMEM); 956f9f848faSopenharmony_ci PDEBUG(("start memcpy, size %d", sizeof(device_t) * dc->maxunit)); 957f9f848faSopenharmony_ci if (oldlist != NULL) 958f9f848faSopenharmony_ci (void)memcpy_s(newlist, sizeof(device_t) * dc->maxunit, oldlist, sizeof(device_t) * dc->maxunit); 959f9f848faSopenharmony_ci PDEBUG(("start memset, maxunit %d, size %d", dc->maxunit, sizeof(device_t) * (newsize - dc->maxunit))); 960f9f848faSopenharmony_ci (void)memset_s(newlist + dc->maxunit, sizeof(device_t) * (newsize - dc->maxunit), 0, 961f9f848faSopenharmony_ci sizeof(device_t) * (newsize - dc->maxunit)); 962f9f848faSopenharmony_ci dc->devices = newlist; 963f9f848faSopenharmony_ci dc->maxunit = newsize; 964f9f848faSopenharmony_ci if (oldlist != NULL) 965f9f848faSopenharmony_ci bsd_free(oldlist, M_BUS); 966f9f848faSopenharmony_ci } 967f9f848faSopenharmony_ci PDEBUG(("now: unit %d in devclass %s", unit, DEVCLANAME(dc))); 968f9f848faSopenharmony_ci 969f9f848faSopenharmony_ci *unitp = unit; 970f9f848faSopenharmony_ci return (0); 971f9f848faSopenharmony_ci} 972f9f848faSopenharmony_ci 973f9f848faSopenharmony_ci/** 974f9f848faSopenharmony_ci * @internal 975f9f848faSopenharmony_ci */ 976f9f848faSopenharmony_cistatic void 977f9f848faSopenharmony_cidevice_set_desc_internal(device_t dev, const char* desc, int copy) 978f9f848faSopenharmony_ci{ 979f9f848faSopenharmony_ci if (dev->desc && (dev->flags & DF_DESCMALLOCED)) { 980f9f848faSopenharmony_ci bsd_free(dev->desc, M_BUS); 981f9f848faSopenharmony_ci dev->flags &= ~DF_DESCMALLOCED; 982f9f848faSopenharmony_ci dev->desc = NULL; 983f9f848faSopenharmony_ci } 984f9f848faSopenharmony_ci 985f9f848faSopenharmony_ci if (copy && desc) { 986f9f848faSopenharmony_ci dev->desc = bsd_malloc(strlen(desc) + 1, M_BUS, M_NOWAIT); 987f9f848faSopenharmony_ci if (dev->desc) { 988f9f848faSopenharmony_ci if (strcpy_s(dev->desc, strlen(desc) + 1, desc) != EOK) { 989f9f848faSopenharmony_ci PDEBUG(("desc internal copy desc failed!\n")); 990f9f848faSopenharmony_ci } 991f9f848faSopenharmony_ci dev->flags |= DF_DESCMALLOCED; 992f9f848faSopenharmony_ci } 993f9f848faSopenharmony_ci } else { 994f9f848faSopenharmony_ci /* Avoid a -Wcast-qual warning */ 995f9f848faSopenharmony_ci dev->desc = (char *)(uintptr_t) desc; 996f9f848faSopenharmony_ci } 997f9f848faSopenharmony_ci 998f9f848faSopenharmony_ci bus_data_generation_update(); 999f9f848faSopenharmony_ci} 1000f9f848faSopenharmony_ci 1001f9f848faSopenharmony_ci/** 1002f9f848faSopenharmony_ci * @brief Set the device's description 1003f9f848faSopenharmony_ci * 1004f9f848faSopenharmony_ci * The value of @c desc should be a string constant that will not 1005f9f848faSopenharmony_ci * change (at least until the description is changed in a subsequent 1006f9f848faSopenharmony_ci * call to device_set_desc() or device_set_desc_copy()). 1007f9f848faSopenharmony_ci */ 1008f9f848faSopenharmony_civoid 1009f9f848faSopenharmony_cidevice_set_desc(device_t dev, const char* desc) 1010f9f848faSopenharmony_ci{ 1011f9f848faSopenharmony_ci device_set_desc_internal(dev, desc, FALSE); 1012f9f848faSopenharmony_ci} 1013f9f848faSopenharmony_ci 1014f9f848faSopenharmony_ci/** 1015f9f848faSopenharmony_ci * @brief Set the device's description 1016f9f848faSopenharmony_ci * 1017f9f848faSopenharmony_ci * The string pointed to by @c desc is copied. Use this function if 1018f9f848faSopenharmony_ci * the device description is generated, (e.g. with sprintf()). 1019f9f848faSopenharmony_ci */ 1020f9f848faSopenharmony_civoid 1021f9f848faSopenharmony_cidevice_set_desc_copy(device_t dev, const char* desc) 1022f9f848faSopenharmony_ci{ 1023f9f848faSopenharmony_ci device_set_desc_internal(dev, desc, TRUE); 1024f9f848faSopenharmony_ci} 1025f9f848faSopenharmony_ci 1026f9f848faSopenharmony_ci/** 1027f9f848faSopenharmony_ci * @brief Return the device's description string 1028f9f848faSopenharmony_ci */ 1029f9f848faSopenharmony_ciconst char * 1030f9f848faSopenharmony_cidevice_get_desc(device_t dev) 1031f9f848faSopenharmony_ci{ 1032f9f848faSopenharmony_ci return (dev->desc); 1033f9f848faSopenharmony_ci} 1034f9f848faSopenharmony_ci 1035f9f848faSopenharmony_ci/** 1036f9f848faSopenharmony_ci * @brief Return the device's softc field 1037f9f848faSopenharmony_ci * 1038f9f848faSopenharmony_ci * The softc is allocated and zeroed when a driver is attached, based 1039f9f848faSopenharmony_ci * on the size field of the driver. 1040f9f848faSopenharmony_ci */ 1041f9f848faSopenharmony_civoid * 1042f9f848faSopenharmony_cidevice_get_softc(device_t dev) 1043f9f848faSopenharmony_ci{ 1044f9f848faSopenharmony_ci return (dev->softc); 1045f9f848faSopenharmony_ci} 1046f9f848faSopenharmony_ci 1047f9f848faSopenharmony_ci/** 1048f9f848faSopenharmony_ci * @brief Set the device's softc field 1049f9f848faSopenharmony_ci * 1050f9f848faSopenharmony_ci * Most drivers do not need to use this since the softc is allocated 1051f9f848faSopenharmony_ci * automatically when the driver is attached. 1052f9f848faSopenharmony_ci */ 1053f9f848faSopenharmony_civoid 1054f9f848faSopenharmony_cidevice_set_softc(device_t dev, void *softc) 1055f9f848faSopenharmony_ci{ 1056f9f848faSopenharmony_ci if (dev->softc && !(dev->flags & DF_EXTERNALSOFTC)) 1057f9f848faSopenharmony_ci bsd_free(dev->softc, M_BUS_SC); 1058f9f848faSopenharmony_ci dev->softc = softc; 1059f9f848faSopenharmony_ci if (dev->softc) 1060f9f848faSopenharmony_ci dev->flags |= DF_EXTERNALSOFTC; 1061f9f848faSopenharmony_ci else 1062f9f848faSopenharmony_ci dev->flags &= ~DF_EXTERNALSOFTC; 1063f9f848faSopenharmony_ci} 1064f9f848faSopenharmony_ci 1065f9f848faSopenharmony_ci/** 1066f9f848faSopenharmony_ci * @brief Free claimed softc 1067f9f848faSopenharmony_ci * 1068f9f848faSopenharmony_ci * Most drivers do not need to use this since the softc is freed 1069f9f848faSopenharmony_ci * automatically when the driver is detached. 1070f9f848faSopenharmony_ci */ 1071f9f848faSopenharmony_civoid 1072f9f848faSopenharmony_cidevice_free_softc(void *softc) 1073f9f848faSopenharmony_ci{ 1074f9f848faSopenharmony_ci bsd_free(softc, M_BUS_SC); 1075f9f848faSopenharmony_ci} 1076f9f848faSopenharmony_ci 1077f9f848faSopenharmony_ci/** 1078f9f848faSopenharmony_ci * @brief Claim softc 1079f9f848faSopenharmony_ci * 1080f9f848faSopenharmony_ci * This function can be used to let the driver free the automatically 1081f9f848faSopenharmony_ci * allocated softc using "device_free_softc()". This function is 1082f9f848faSopenharmony_ci * useful when the driver is refcounting the softc and the softc 1083f9f848faSopenharmony_ci * cannot be freed when the "device_detach" method is called. 1084f9f848faSopenharmony_ci */ 1085f9f848faSopenharmony_civoid 1086f9f848faSopenharmony_cidevice_claim_softc(device_t dev) 1087f9f848faSopenharmony_ci{ 1088f9f848faSopenharmony_ci if (dev->softc) 1089f9f848faSopenharmony_ci dev->flags |= DF_EXTERNALSOFTC; 1090f9f848faSopenharmony_ci else 1091f9f848faSopenharmony_ci dev->flags &= ~DF_EXTERNALSOFTC; 1092f9f848faSopenharmony_ci} 1093f9f848faSopenharmony_ci 1094f9f848faSopenharmony_ci/** 1095f9f848faSopenharmony_ci * @brief Get the device's ivars field 1096f9f848faSopenharmony_ci * 1097f9f848faSopenharmony_ci * The ivars field is used by the parent device to store per-device 1098f9f848faSopenharmony_ci * state (e.g. the physical location of the device or a list of 1099f9f848faSopenharmony_ci * resources). 1100f9f848faSopenharmony_ci */ 1101f9f848faSopenharmony_civoid * 1102f9f848faSopenharmony_cidevice_get_ivars(device_t dev) 1103f9f848faSopenharmony_ci{ 1104f9f848faSopenharmony_ci 1105f9f848faSopenharmony_ci KASSERT(dev != NULL, ("device_get_ivars(NULL, ...)")); 1106f9f848faSopenharmony_ci return (dev->ivars); 1107f9f848faSopenharmony_ci} 1108f9f848faSopenharmony_ci 1109f9f848faSopenharmony_ci/** 1110f9f848faSopenharmony_ci * @brief Set the device's ivars field 1111f9f848faSopenharmony_ci */ 1112f9f848faSopenharmony_civoid 1113f9f848faSopenharmony_cidevice_set_ivars(device_t dev, void * ivars) 1114f9f848faSopenharmony_ci{ 1115f9f848faSopenharmony_ci 1116f9f848faSopenharmony_ci KASSERT(dev != NULL, ("device_set_ivars(NULL, ...)")); 1117f9f848faSopenharmony_ci dev->ivars = ivars; 1118f9f848faSopenharmony_ci} 1119f9f848faSopenharmony_ci 1120f9f848faSopenharmony_ci/** 1121f9f848faSopenharmony_ci * @brief Return the device's state 1122f9f848faSopenharmony_ci */ 1123f9f848faSopenharmony_cidevice_state_t 1124f9f848faSopenharmony_cidevice_get_state(device_t dev) 1125f9f848faSopenharmony_ci{ 1126f9f848faSopenharmony_ci return (dev->state); 1127f9f848faSopenharmony_ci} 1128f9f848faSopenharmony_ci 1129f9f848faSopenharmony_ci/** 1130f9f848faSopenharmony_ci * @brief Set the DF_ENABLED flag for the device 1131f9f848faSopenharmony_ci */ 1132f9f848faSopenharmony_civoid 1133f9f848faSopenharmony_cidevice_enable(device_t dev) 1134f9f848faSopenharmony_ci{ 1135f9f848faSopenharmony_ci dev->flags |= DF_ENABLED; 1136f9f848faSopenharmony_ci} 1137f9f848faSopenharmony_ci 1138f9f848faSopenharmony_ci/** 1139f9f848faSopenharmony_ci * @brief Clear the DF_ENABLED flag for the device 1140f9f848faSopenharmony_ci */ 1141f9f848faSopenharmony_civoid 1142f9f848faSopenharmony_cidevice_disable(device_t dev) 1143f9f848faSopenharmony_ci{ 1144f9f848faSopenharmony_ci dev->flags &= ~DF_ENABLED; 1145f9f848faSopenharmony_ci} 1146f9f848faSopenharmony_ci 1147f9f848faSopenharmony_ci/** 1148f9f848faSopenharmony_ci * @brief Increment the busy counter for the device 1149f9f848faSopenharmony_ci */ 1150f9f848faSopenharmony_civoid 1151f9f848faSopenharmony_cidevice_busy(device_t dev) 1152f9f848faSopenharmony_ci{ 1153f9f848faSopenharmony_ci if (dev->state < DS_ATTACHING) 1154f9f848faSopenharmony_ci panic("device_busy: called for unattached device"); 1155f9f848faSopenharmony_ci if (dev->busy == 0 && dev->parent) 1156f9f848faSopenharmony_ci device_busy(dev->parent); 1157f9f848faSopenharmony_ci dev->busy++; 1158f9f848faSopenharmony_ci if (dev->state == DS_ATTACHED) 1159f9f848faSopenharmony_ci dev->state = DS_BUSY; 1160f9f848faSopenharmony_ci} 1161f9f848faSopenharmony_ci 1162f9f848faSopenharmony_ci/** 1163f9f848faSopenharmony_ci * @brief Decrement the busy counter for the device 1164f9f848faSopenharmony_ci */ 1165f9f848faSopenharmony_civoid 1166f9f848faSopenharmony_cidevice_unbusy(device_t dev) 1167f9f848faSopenharmony_ci{ 1168f9f848faSopenharmony_ci if (dev->busy != 0 && dev->state != DS_BUSY && 1169f9f848faSopenharmony_ci dev->state != DS_ATTACHING) 1170f9f848faSopenharmony_ci panic("device_unbusy: called for non-busy device %s", 1171f9f848faSopenharmony_ci device_get_nameunit(dev)); 1172f9f848faSopenharmony_ci dev->busy--; 1173f9f848faSopenharmony_ci if (dev->busy == 0) { 1174f9f848faSopenharmony_ci if (dev->parent) 1175f9f848faSopenharmony_ci device_unbusy(dev->parent); 1176f9f848faSopenharmony_ci if (dev->state == DS_BUSY) 1177f9f848faSopenharmony_ci dev->state = DS_ATTACHED; 1178f9f848faSopenharmony_ci } 1179f9f848faSopenharmony_ci} 1180f9f848faSopenharmony_ci 1181f9f848faSopenharmony_ci/** 1182f9f848faSopenharmony_ci * @brief Set the DF_QUIET flag for the device 1183f9f848faSopenharmony_ci */ 1184f9f848faSopenharmony_civoid 1185f9f848faSopenharmony_cidevice_quiet(device_t dev) 1186f9f848faSopenharmony_ci{ 1187f9f848faSopenharmony_ci dev->flags |= DF_QUIET; 1188f9f848faSopenharmony_ci} 1189f9f848faSopenharmony_ci 1190f9f848faSopenharmony_ci/** 1191f9f848faSopenharmony_ci * @brief Clear the DF_QUIET flag for the device 1192f9f848faSopenharmony_ci */ 1193f9f848faSopenharmony_civoid 1194f9f848faSopenharmony_cidevice_verbose(device_t dev) 1195f9f848faSopenharmony_ci{ 1196f9f848faSopenharmony_ci dev->flags &= ~DF_QUIET; 1197f9f848faSopenharmony_ci} 1198f9f848faSopenharmony_ci 1199f9f848faSopenharmony_ci/** 1200f9f848faSopenharmony_ci * @brief Return non-zero if the DF_QUIET flag is set on the device 1201f9f848faSopenharmony_ci */ 1202f9f848faSopenharmony_ciint 1203f9f848faSopenharmony_cidevice_is_quiet(device_t dev) 1204f9f848faSopenharmony_ci{ 1205f9f848faSopenharmony_ci return ((dev->flags & DF_QUIET) != 0); 1206f9f848faSopenharmony_ci} 1207f9f848faSopenharmony_ci 1208f9f848faSopenharmony_ci/** 1209f9f848faSopenharmony_ci * @brief Return non-zero if the DF_ENABLED flag is set on the device 1210f9f848faSopenharmony_ci */ 1211f9f848faSopenharmony_ciint 1212f9f848faSopenharmony_cidevice_is_enabled(device_t dev) 1213f9f848faSopenharmony_ci{ 1214f9f848faSopenharmony_ci return ((dev->flags & DF_ENABLED) != 0); 1215f9f848faSopenharmony_ci} 1216f9f848faSopenharmony_ci 1217f9f848faSopenharmony_ci/** 1218f9f848faSopenharmony_ci * @brief Return non-zero if the device was successfully probed 1219f9f848faSopenharmony_ci */ 1220f9f848faSopenharmony_ciint 1221f9f848faSopenharmony_cidevice_is_alive(device_t dev) 1222f9f848faSopenharmony_ci{ 1223f9f848faSopenharmony_ci return (dev->state >= DS_ALIVE); 1224f9f848faSopenharmony_ci} 1225f9f848faSopenharmony_ci 1226f9f848faSopenharmony_ci/** 1227f9f848faSopenharmony_ci * @brief Return non-zero if the device currently has a driver 1228f9f848faSopenharmony_ci * attached to it 1229f9f848faSopenharmony_ci */ 1230f9f848faSopenharmony_ciint 1231f9f848faSopenharmony_cidevice_is_attached(device_t dev) 1232f9f848faSopenharmony_ci{ 1233f9f848faSopenharmony_ci return (dev->state >= DS_ATTACHED); 1234f9f848faSopenharmony_ci} 1235f9f848faSopenharmony_ci 1236f9f848faSopenharmony_ci/** 1237f9f848faSopenharmony_ci * @brief Return non-zero if the device is currently suspended. 1238f9f848faSopenharmony_ci */ 1239f9f848faSopenharmony_ciint 1240f9f848faSopenharmony_cidevice_is_suspended(device_t dev) 1241f9f848faSopenharmony_ci{ 1242f9f848faSopenharmony_ci return ((dev->flags & DF_SUSPENDED) != 0); 1243f9f848faSopenharmony_ci} 1244f9f848faSopenharmony_ci 1245f9f848faSopenharmony_ci 1246f9f848faSopenharmony_ci 1247f9f848faSopenharmony_ci/** 1248f9f848faSopenharmony_ci * @brief Return a string containing the device's devclass name 1249f9f848faSopenharmony_ci * followed by an ascii representation of the device's unit number 1250f9f848faSopenharmony_ci * (e.g. @c "foo2"). 1251f9f848faSopenharmony_ci */ 1252f9f848faSopenharmony_ciconst char * 1253f9f848faSopenharmony_cidevice_get_nameunit(device_t dev) 1254f9f848faSopenharmony_ci{ 1255f9f848faSopenharmony_ci return (dev->nameunit); 1256f9f848faSopenharmony_ci} 1257f9f848faSopenharmony_ci 1258f9f848faSopenharmony_ci/** 1259f9f848faSopenharmony_ci * @internal 1260f9f848faSopenharmony_ci * @brief Add a device to a devclass 1261f9f848faSopenharmony_ci * 1262f9f848faSopenharmony_ci * A unit number is allocated for the device (using the device's 1263f9f848faSopenharmony_ci * preferred unit number if any) and the device is registered in the 1264f9f848faSopenharmony_ci * devclass. This allows the device to be looked up by its unit 1265f9f848faSopenharmony_ci * number, e.g. by decoding a dev_t minor number. 1266f9f848faSopenharmony_ci * 1267f9f848faSopenharmony_ci * @param dc the devclass to add to 1268f9f848faSopenharmony_ci * @param dev the device to add 1269f9f848faSopenharmony_ci * 1270f9f848faSopenharmony_ci * @retval 0 success 1271f9f848faSopenharmony_ci * @retval EEXIST the requested unit number is already allocated 1272f9f848faSopenharmony_ci * @retval ENOMEM memory allocation failure 1273f9f848faSopenharmony_ci */ 1274f9f848faSopenharmony_cistatic int 1275f9f848faSopenharmony_cidevclass_add_device(devclass_t dc, device_t dev) 1276f9f848faSopenharmony_ci{ 1277f9f848faSopenharmony_ci int buflen, error; 1278f9f848faSopenharmony_ci 1279f9f848faSopenharmony_ci PDEBUG(("%s in devclass %s", DEVICENAME(dev), DEVCLANAME(dc))); 1280f9f848faSopenharmony_ci 1281f9f848faSopenharmony_ci buflen = snprintf(NULL, 0, "%s%d$", dc->name, INT_MAX); 1282f9f848faSopenharmony_ci if (buflen < 0) 1283f9f848faSopenharmony_ci return (ENOMEM); 1284f9f848faSopenharmony_ci dev->nameunit = bsd_malloc(buflen, M_BUS, M_NOWAIT|M_ZERO); 1285f9f848faSopenharmony_ci if (!dev->nameunit) 1286f9f848faSopenharmony_ci return (ENOMEM); 1287f9f848faSopenharmony_ci 1288f9f848faSopenharmony_ci if ((error = devclass_alloc_unit(dc, dev, &dev->unit)) != 0) { 1289f9f848faSopenharmony_ci bsd_free(dev->nameunit, M_BUS); 1290f9f848faSopenharmony_ci dev->nameunit = NULL; 1291f9f848faSopenharmony_ci return (error); 1292f9f848faSopenharmony_ci } 1293f9f848faSopenharmony_ci dc->devices[dev->unit] = dev; 1294f9f848faSopenharmony_ci dev->devclass = dc; 1295f9f848faSopenharmony_ci if (snprintf_s(dev->nameunit, buflen, buflen - 1, "%s%d", dc->name, dev->unit) < 0) { 1296f9f848faSopenharmony_ci bsd_free(dev->nameunit, M_BUS); 1297f9f848faSopenharmony_ci dev->nameunit = NULL; 1298f9f848faSopenharmony_ci return (ENOMEM); 1299f9f848faSopenharmony_ci } 1300f9f848faSopenharmony_ci PDEBUG(("dev->nameunit : %s", dev->nameunit)); 1301f9f848faSopenharmony_ci 1302f9f848faSopenharmony_ci return (0); 1303f9f848faSopenharmony_ci} 1304f9f848faSopenharmony_ci 1305f9f848faSopenharmony_ci/** 1306f9f848faSopenharmony_ci * @internal 1307f9f848faSopenharmony_ci * @brief Delete a device from a devclass 1308f9f848faSopenharmony_ci * 1309f9f848faSopenharmony_ci * The device is removed from the devclass's device list and its unit 1310f9f848faSopenharmony_ci * number is freed. 1311f9f848faSopenharmony_ci 1312f9f848faSopenharmony_ci * @param dc the devclass to delete from 1313f9f848faSopenharmony_ci * @param dev the device to delete 1314f9f848faSopenharmony_ci * 1315f9f848faSopenharmony_ci * @retval 0 success 1316f9f848faSopenharmony_ci */ 1317f9f848faSopenharmony_cistatic int 1318f9f848faSopenharmony_cidevclass_delete_device(devclass_t dc, device_t dev) 1319f9f848faSopenharmony_ci{ 1320f9f848faSopenharmony_ci if (!dc || !dev) 1321f9f848faSopenharmony_ci return (0); 1322f9f848faSopenharmony_ci 1323f9f848faSopenharmony_ci PDEBUG(("%s in devclass %s", DEVICENAME(dev), DEVCLANAME(dc))); 1324f9f848faSopenharmony_ci 1325f9f848faSopenharmony_ci if (dev->devclass != dc || dc->devices[dev->unit] != dev) 1326f9f848faSopenharmony_ci panic("devclass_delete_device: inconsistent device class"); 1327f9f848faSopenharmony_ci dc->devices[dev->unit] = NULL; 1328f9f848faSopenharmony_ci if (dev->flags & DF_WILDCARD) 1329f9f848faSopenharmony_ci dev->unit = -1; 1330f9f848faSopenharmony_ci dev->devclass = NULL; 1331f9f848faSopenharmony_ci bsd_free(dev->nameunit, M_BUS); 1332f9f848faSopenharmony_ci dev->nameunit = NULL; 1333f9f848faSopenharmony_ci 1334f9f848faSopenharmony_ci return (0); 1335f9f848faSopenharmony_ci} 1336f9f848faSopenharmony_ci 1337f9f848faSopenharmony_ci/** 1338f9f848faSopenharmony_ci * @internal 1339f9f848faSopenharmony_ci * @brief Make a new device and add it as a child of @p parent 1340f9f848faSopenharmony_ci * 1341f9f848faSopenharmony_ci * @param parent the parent of the new device 1342f9f848faSopenharmony_ci * @param name the devclass name of the new device or @c NULL 1343f9f848faSopenharmony_ci * to leave the devclass unspecified 1344f9f848faSopenharmony_ci * @parem unit the unit number of the new device of @c -1 to 1345f9f848faSopenharmony_ci * leave the unit number unspecified 1346f9f848faSopenharmony_ci * 1347f9f848faSopenharmony_ci * @returns the new device 1348f9f848faSopenharmony_ci */ 1349f9f848faSopenharmony_cistatic device_t 1350f9f848faSopenharmony_cimake_device(device_t parent, const char *name, int unit) 1351f9f848faSopenharmony_ci{ 1352f9f848faSopenharmony_ci device_t dev; 1353f9f848faSopenharmony_ci devclass_t dc; 1354f9f848faSopenharmony_ci 1355f9f848faSopenharmony_ci PDEBUG(("%s at %s as unit %d", name, DEVICENAME(parent), unit)); 1356f9f848faSopenharmony_ci 1357f9f848faSopenharmony_ci if (name) { 1358f9f848faSopenharmony_ci dc = devclass_find_internal(name, NULL, TRUE); 1359f9f848faSopenharmony_ci if (!dc) { 1360f9f848faSopenharmony_ci printf("make_device: can't find device class %s\n", 1361f9f848faSopenharmony_ci name); 1362f9f848faSopenharmony_ci return (NULL); 1363f9f848faSopenharmony_ci } 1364f9f848faSopenharmony_ci } else { 1365f9f848faSopenharmony_ci dc = NULL; 1366f9f848faSopenharmony_ci } 1367f9f848faSopenharmony_ci 1368f9f848faSopenharmony_ci dev = bsd_malloc(sizeof(struct device), 0, M_NOWAIT|M_ZERO); 1369f9f848faSopenharmony_ci if (!dev) 1370f9f848faSopenharmony_ci return (NULL); 1371f9f848faSopenharmony_ci 1372f9f848faSopenharmony_ci dev->parent = parent; 1373f9f848faSopenharmony_ci TAILQ_INIT(&dev->children); 1374f9f848faSopenharmony_ci kobj_init((kobj_t) dev, &null_class); 1375f9f848faSopenharmony_ci dev->driver = NULL; 1376f9f848faSopenharmony_ci dev->devclass = NULL; 1377f9f848faSopenharmony_ci dev->unit = unit; 1378f9f848faSopenharmony_ci dev->nameunit = NULL; 1379f9f848faSopenharmony_ci dev->desc = NULL; 1380f9f848faSopenharmony_ci dev->busy = 0; 1381f9f848faSopenharmony_ci dev->devflags = 0; 1382f9f848faSopenharmony_ci dev->flags = DF_ENABLED; 1383f9f848faSopenharmony_ci dev->order = 0; 1384f9f848faSopenharmony_ci if (unit == -1) 1385f9f848faSopenharmony_ci dev->flags |= DF_WILDCARD; 1386f9f848faSopenharmony_ci if (name) { 1387f9f848faSopenharmony_ci dev->flags |= DF_FIXEDCLASS; 1388f9f848faSopenharmony_ci if (devclass_add_device(dc, dev)) { 1389f9f848faSopenharmony_ci kobj_delete((kobj_t) dev, NULL); 1390f9f848faSopenharmony_ci return (NULL); 1391f9f848faSopenharmony_ci } 1392f9f848faSopenharmony_ci } 1393f9f848faSopenharmony_ci dev->ivars = NULL; 1394f9f848faSopenharmony_ci dev->softc = NULL; 1395f9f848faSopenharmony_ci 1396f9f848faSopenharmony_ci dev->state = DS_NOTPRESENT; 1397f9f848faSopenharmony_ci 1398f9f848faSopenharmony_ci PDEBUG(("bus_data_devices (%p) ", &bus_data_devices)); 1399f9f848faSopenharmony_ci TAILQ_INSERT_TAIL(&bus_data_devices, dev, devlink); 1400f9f848faSopenharmony_ci bus_data_generation_update(); 1401f9f848faSopenharmony_ci 1402f9f848faSopenharmony_ci PDEBUG(("%s at %s as unit %d success", name, DEVICENAME(parent), unit)); 1403f9f848faSopenharmony_ci return (dev); 1404f9f848faSopenharmony_ci} 1405f9f848faSopenharmony_ci 1406f9f848faSopenharmony_ci/** 1407f9f848faSopenharmony_ci * @internal 1408f9f848faSopenharmony_ci * @brief Print a description of a device. 1409f9f848faSopenharmony_ci */ 1410f9f848faSopenharmony_cistatic int 1411f9f848faSopenharmony_cidevice_print_child(device_t dev, device_t child) 1412f9f848faSopenharmony_ci{ 1413f9f848faSopenharmony_ci int retval = 0; 1414f9f848faSopenharmony_ci 1415f9f848faSopenharmony_ci if (device_is_alive(child)) 1416f9f848faSopenharmony_ci retval += BUS_PRINT_CHILD(dev, child); 1417f9f848faSopenharmony_ci else 1418f9f848faSopenharmony_ci retval += device_printf(child, " not found\n"); 1419f9f848faSopenharmony_ci 1420f9f848faSopenharmony_ci return (retval); 1421f9f848faSopenharmony_ci} 1422f9f848faSopenharmony_ci 1423f9f848faSopenharmony_ci/** 1424f9f848faSopenharmony_ci * @brief Create a new device 1425f9f848faSopenharmony_ci * 1426f9f848faSopenharmony_ci * This creates a new device and adds it as a child of an existing 1427f9f848faSopenharmony_ci * parent device. The new device will be added after the last existing 1428f9f848faSopenharmony_ci * child with order zero. 1429f9f848faSopenharmony_ci * 1430f9f848faSopenharmony_ci * @param dev the device which will be the parent of the 1431f9f848faSopenharmony_ci * new child device 1432f9f848faSopenharmony_ci * @param name devclass name for new device or @c NULL if not 1433f9f848faSopenharmony_ci * specified 1434f9f848faSopenharmony_ci * @param unit unit number for new device or @c -1 if not 1435f9f848faSopenharmony_ci * specified 1436f9f848faSopenharmony_ci * 1437f9f848faSopenharmony_ci * @returns the new device 1438f9f848faSopenharmony_ci */ 1439f9f848faSopenharmony_cidevice_t 1440f9f848faSopenharmony_cidevice_add_child(device_t dev, const char *name, int unit) 1441f9f848faSopenharmony_ci{ 1442f9f848faSopenharmony_ci return (device_add_child_ordered(dev, 0, name, unit)); 1443f9f848faSopenharmony_ci} 1444f9f848faSopenharmony_ci 1445f9f848faSopenharmony_cidevice_t 1446f9f848faSopenharmony_cibus_get_device(device_t dev, const char *name) 1447f9f848faSopenharmony_ci{ 1448f9f848faSopenharmony_ci device_t child; 1449f9f848faSopenharmony_ci 1450f9f848faSopenharmony_ci PDEBUG(("+")); 1451f9f848faSopenharmony_ci TAILQ_FOREACH(child, &dev->children, link) { 1452f9f848faSopenharmony_ci if (!strcmp(device_get_name(child), name)) 1453f9f848faSopenharmony_ci return (child); 1454f9f848faSopenharmony_ci } 1455f9f848faSopenharmony_ci PDEBUG(("-")); 1456f9f848faSopenharmony_ci return (NULL); 1457f9f848faSopenharmony_ci} 1458f9f848faSopenharmony_ci 1459f9f848faSopenharmony_ci/** 1460f9f848faSopenharmony_ci * @brief Create a new device 1461f9f848faSopenharmony_ci * 1462f9f848faSopenharmony_ci * This creates a new device and adds it as a child of an existing 1463f9f848faSopenharmony_ci * parent device. The new device will be added after the last existing 1464f9f848faSopenharmony_ci * child with the same order. 1465f9f848faSopenharmony_ci * 1466f9f848faSopenharmony_ci * @param dev the device which will be the parent of the 1467f9f848faSopenharmony_ci * new child device 1468f9f848faSopenharmony_ci * @param order a value which is used to partially sort the 1469f9f848faSopenharmony_ci * children of @p dev - devices created using 1470f9f848faSopenharmony_ci * lower values of @p order appear first in @p 1471f9f848faSopenharmony_ci * dev's list of children 1472f9f848faSopenharmony_ci * @param name devclass name for new device or @c NULL if not 1473f9f848faSopenharmony_ci * specified 1474f9f848faSopenharmony_ci * @param unit unit number for new device or @c -1 if not 1475f9f848faSopenharmony_ci * specified 1476f9f848faSopenharmony_ci * 1477f9f848faSopenharmony_ci * @returns the new device 1478f9f848faSopenharmony_ci */ 1479f9f848faSopenharmony_cidevice_t 1480f9f848faSopenharmony_cidevice_add_child_ordered(device_t dev, u_int order, const char *name, int unit) 1481f9f848faSopenharmony_ci{ 1482f9f848faSopenharmony_ci device_t child; 1483f9f848faSopenharmony_ci device_t place; 1484f9f848faSopenharmony_ci 1485f9f848faSopenharmony_ci PDEBUG(("%s at %s with order %u as unit %d", 1486f9f848faSopenharmony_ci name, DEVICENAME(dev), order, unit)); 1487f9f848faSopenharmony_ci KASSERT(name != NULL || unit == -1, 1488f9f848faSopenharmony_ci ("child device with wildcard name and specific unit number")); 1489f9f848faSopenharmony_ci 1490f9f848faSopenharmony_ci child = make_device(dev, name, unit); 1491f9f848faSopenharmony_ci if (child == NULL) 1492f9f848faSopenharmony_ci return (child); 1493f9f848faSopenharmony_ci child->order = order; 1494f9f848faSopenharmony_ci 1495f9f848faSopenharmony_ci TAILQ_FOREACH(place, &dev->children, link) { 1496f9f848faSopenharmony_ci if (place->order > order) 1497f9f848faSopenharmony_ci break; 1498f9f848faSopenharmony_ci } 1499f9f848faSopenharmony_ci 1500f9f848faSopenharmony_ci if (place) { 1501f9f848faSopenharmony_ci /* 1502f9f848faSopenharmony_ci * The device 'place' is the first device whose order is 1503f9f848faSopenharmony_ci * greater than the new child. 1504f9f848faSopenharmony_ci */ 1505f9f848faSopenharmony_ci TAILQ_INSERT_BEFORE(place, child, link); 1506f9f848faSopenharmony_ci } else { 1507f9f848faSopenharmony_ci /* 1508f9f848faSopenharmony_ci * The new child's order is greater or equal to the order of 1509f9f848faSopenharmony_ci * any existing device. Add the child to the tail of the list. 1510f9f848faSopenharmony_ci */ 1511f9f848faSopenharmony_ci TAILQ_INSERT_TAIL(&dev->children, child, link); 1512f9f848faSopenharmony_ci } 1513f9f848faSopenharmony_ci 1514f9f848faSopenharmony_ci bus_data_generation_update(); 1515f9f848faSopenharmony_ci PDEBUG(("%s at %s with order %u as unit %d success", 1516f9f848faSopenharmony_ci name, DEVICENAME(dev), order, unit)); 1517f9f848faSopenharmony_ci return (child); 1518f9f848faSopenharmony_ci} 1519f9f848faSopenharmony_ci 1520f9f848faSopenharmony_ci/** 1521f9f848faSopenharmony_ci * @brief Delete a device 1522f9f848faSopenharmony_ci * 1523f9f848faSopenharmony_ci * This function deletes a device along with all of its children. If 1524f9f848faSopenharmony_ci * the device currently has a driver attached to it, the device is 1525f9f848faSopenharmony_ci * detached first using device_detach(). 1526f9f848faSopenharmony_ci * 1527f9f848faSopenharmony_ci * @param dev the parent device 1528f9f848faSopenharmony_ci * @param child the device to delete 1529f9f848faSopenharmony_ci * 1530f9f848faSopenharmony_ci * @retval 0 success 1531f9f848faSopenharmony_ci * @retval non-zero a unit error code describing the error 1532f9f848faSopenharmony_ci */ 1533f9f848faSopenharmony_ciint 1534f9f848faSopenharmony_cidevice_delete_child(device_t dev, device_t child) 1535f9f848faSopenharmony_ci{ 1536f9f848faSopenharmony_ci int error; 1537f9f848faSopenharmony_ci device_t grandchild; 1538f9f848faSopenharmony_ci 1539f9f848faSopenharmony_ci PDEBUG(("%s from %s", DEVICENAME(child), DEVICENAME(dev))); 1540f9f848faSopenharmony_ci 1541f9f848faSopenharmony_ci /* detach parent before deleting children, if any */ 1542f9f848faSopenharmony_ci if ((error = device_detach(child)) != 0) 1543f9f848faSopenharmony_ci return (error); 1544f9f848faSopenharmony_ci 1545f9f848faSopenharmony_ci /* remove children second */ 1546f9f848faSopenharmony_ci while ((grandchild = TAILQ_FIRST(&child->children)) != NULL) { 1547f9f848faSopenharmony_ci error = device_delete_child(child, grandchild); 1548f9f848faSopenharmony_ci if (error) 1549f9f848faSopenharmony_ci return (error); 1550f9f848faSopenharmony_ci } 1551f9f848faSopenharmony_ci 1552f9f848faSopenharmony_ci if (child->devclass) 1553f9f848faSopenharmony_ci devclass_delete_device(child->devclass, child); 1554f9f848faSopenharmony_ci if (child->parent) 1555f9f848faSopenharmony_ci BUS_CHILD_DELETED(dev, child); 1556f9f848faSopenharmony_ci TAILQ_REMOVE(&dev->children, child, link); 1557f9f848faSopenharmony_ci TAILQ_REMOVE(&bus_data_devices, child, devlink); 1558f9f848faSopenharmony_ci kobj_delete((kobj_t) child, M_BUS); 1559f9f848faSopenharmony_ci 1560f9f848faSopenharmony_ci bus_data_generation_update(); 1561f9f848faSopenharmony_ci return (0); 1562f9f848faSopenharmony_ci} 1563f9f848faSopenharmony_ci 1564f9f848faSopenharmony_ci/** 1565f9f848faSopenharmony_ci * @brief Delete all children devices of the given device, if any. 1566f9f848faSopenharmony_ci * 1567f9f848faSopenharmony_ci * This function deletes all children devices of the given device, if 1568f9f848faSopenharmony_ci * any, using the device_delete_child() function for each device it 1569f9f848faSopenharmony_ci * finds. If a child device cannot be deleted, this function will 1570f9f848faSopenharmony_ci * return an error code. 1571f9f848faSopenharmony_ci * 1572f9f848faSopenharmony_ci * @param dev the parent device 1573f9f848faSopenharmony_ci * 1574f9f848faSopenharmony_ci * @retval 0 success 1575f9f848faSopenharmony_ci * @retval non-zero a device would not detach 1576f9f848faSopenharmony_ci */ 1577f9f848faSopenharmony_ciint 1578f9f848faSopenharmony_cidevice_delete_children(device_t dev) 1579f9f848faSopenharmony_ci{ 1580f9f848faSopenharmony_ci device_t child; 1581f9f848faSopenharmony_ci int error; 1582f9f848faSopenharmony_ci 1583f9f848faSopenharmony_ci PDEBUG(("Deleting all children of %s", DEVICENAME(dev))); 1584f9f848faSopenharmony_ci 1585f9f848faSopenharmony_ci error = 0; 1586f9f848faSopenharmony_ci 1587f9f848faSopenharmony_ci while ((child = TAILQ_FIRST(&dev->children)) != NULL) { 1588f9f848faSopenharmony_ci error = device_delete_child(dev, child); 1589f9f848faSopenharmony_ci if (error) { 1590f9f848faSopenharmony_ci PDEBUG(("Failed deleting %s", DEVICENAME(child))); 1591f9f848faSopenharmony_ci break; 1592f9f848faSopenharmony_ci } 1593f9f848faSopenharmony_ci } 1594f9f848faSopenharmony_ci return (error); 1595f9f848faSopenharmony_ci} 1596f9f848faSopenharmony_ci 1597f9f848faSopenharmony_ci/** 1598f9f848faSopenharmony_ci * @brief Probe a device and attach a driver if possible 1599f9f848faSopenharmony_ci * 1600f9f848faSopenharmony_ci * calls device_probe() and attaches if that was successful. 1601f9f848faSopenharmony_ci */ 1602f9f848faSopenharmony_ciint 1603f9f848faSopenharmony_cidevice_probe_and_attach(device_t dev) 1604f9f848faSopenharmony_ci{ 1605f9f848faSopenharmony_ci int error; 1606f9f848faSopenharmony_ci 1607f9f848faSopenharmony_ci PDEBUG(("+")); 1608f9f848faSopenharmony_ci GIANT_REQUIRED; 1609f9f848faSopenharmony_ci 1610f9f848faSopenharmony_ci error = device_probe(dev); 1611f9f848faSopenharmony_ci if (error == -1) 1612f9f848faSopenharmony_ci return (0); 1613f9f848faSopenharmony_ci else if (error != 0) 1614f9f848faSopenharmony_ci return (error); 1615f9f848faSopenharmony_ci 1616f9f848faSopenharmony_ci //CURVNET_SET_QUIET(vnet0); 1617f9f848faSopenharmony_ci error = device_attach(dev); 1618f9f848faSopenharmony_ci //CURVNET_RESTORE(); 1619f9f848faSopenharmony_ci PDEBUG(("-")); 1620f9f848faSopenharmony_ci return error; 1621f9f848faSopenharmony_ci} 1622f9f848faSopenharmony_ci 1623f9f848faSopenharmony_ci/** 1624f9f848faSopenharmony_ci * @brief Attach a device driver to a device 1625f9f848faSopenharmony_ci * 1626f9f848faSopenharmony_ci * This function is a wrapper around the DEVICE_ATTACH() driver 1627f9f848faSopenharmony_ci * method. In addition to calling DEVICE_ATTACH(), it initialises the 1628f9f848faSopenharmony_ci * device's sysctl tree, optionally prints a description of the device 1629f9f848faSopenharmony_ci * and queues a notification event for user-based device management 1630f9f848faSopenharmony_ci * services. 1631f9f848faSopenharmony_ci * 1632f9f848faSopenharmony_ci * Normally this function is only called internally from 1633f9f848faSopenharmony_ci * device_probe_and_attach(). 1634f9f848faSopenharmony_ci * 1635f9f848faSopenharmony_ci * @param dev the device to initialise 1636f9f848faSopenharmony_ci * 1637f9f848faSopenharmony_ci * @retval 0 success 1638f9f848faSopenharmony_ci * @retval ENXIO no driver was found 1639f9f848faSopenharmony_ci * @retval ENOMEM memory allocation failure 1640f9f848faSopenharmony_ci * @retval non-zero some other unix error code 1641f9f848faSopenharmony_ci */ 1642f9f848faSopenharmony_ciint 1643f9f848faSopenharmony_cidevice_attach(device_t dev) 1644f9f848faSopenharmony_ci{ 1645f9f848faSopenharmony_ci uint64_t attachtime; 1646f9f848faSopenharmony_ci int error; 1647f9f848faSopenharmony_ci PDEBUG(("+")); 1648f9f848faSopenharmony_ci 1649f9f848faSopenharmony_ci //if (resource_disabled(dev->driver->name, dev->unit)) { 1650f9f848faSopenharmony_ci // device_disable(dev); 1651f9f848faSopenharmony_ci // if (bootverbose) 1652f9f848faSopenharmony_ci // device_printf(dev, "disabled via hints entry\n"); 1653f9f848faSopenharmony_ci // return (ENXIO); 1654f9f848faSopenharmony_ci //} 1655f9f848faSopenharmony_ci 1656f9f848faSopenharmony_ci //device_sysctl_init(dev); 1657f9f848faSopenharmony_ci if (!device_is_quiet(dev)) 1658f9f848faSopenharmony_ci device_print_child(dev->parent, dev); 1659f9f848faSopenharmony_ci // attachtime = get_cyclecount(); 1660f9f848faSopenharmony_ci dev->state = DS_ATTACHING; 1661f9f848faSopenharmony_ci if ((error = DEVICE_ATTACH(dev)) != 0) { 1662f9f848faSopenharmony_ci printf("device_attach: %s%d attach returned %d\n", 1663f9f848faSopenharmony_ci dev->driver->name, dev->unit, error); 1664f9f848faSopenharmony_ci if (!(dev->flags & DF_FIXEDCLASS)) 1665f9f848faSopenharmony_ci devclass_delete_device(dev->devclass, dev); 1666f9f848faSopenharmony_ci (void)device_set_driver(dev, NULL); 1667f9f848faSopenharmony_ci //device_sysctl_fini(dev); 1668f9f848faSopenharmony_ci KASSERT(dev->busy == 0, ("attach failed but busy")); 1669f9f848faSopenharmony_ci dev->state = DS_NOTPRESENT; 1670f9f848faSopenharmony_ci return (error); 1671f9f848faSopenharmony_ci } 1672f9f848faSopenharmony_ci // attachtime = get_cyclecount() - attachtime; 1673f9f848faSopenharmony_ci /* 1674f9f848faSopenharmony_ci * 4 bits per device is a reasonable value for desktop and server 1675f9f848faSopenharmony_ci * hardware with good get_cyclecount() implementations, but WILL 1676f9f848faSopenharmony_ci * need to be adjusted on other platforms. 1677f9f848faSopenharmony_ci */ 1678f9f848faSopenharmony_ci#define RANDOM_PROBE_BIT_GUESS 4 1679f9f848faSopenharmony_ci if (bootverbose) 1680f9f848faSopenharmony_ci printf("random: harvesting attach, %zu bytes (%d bits) from %s%d\n", 1681f9f848faSopenharmony_ci sizeof(attachtime), RANDOM_PROBE_BIT_GUESS, 1682f9f848faSopenharmony_ci dev->driver->name, dev->unit); 1683f9f848faSopenharmony_ci //random_harvest_direct(&attachtime, sizeof(attachtime), 1684f9f848faSopenharmony_ci // RANDOM_PROBE_BIT_GUESS, RANDOM_ATTACH); 1685f9f848faSopenharmony_ci //device_sysctl_update(dev); 1686f9f848faSopenharmony_ci if (dev->busy) 1687f9f848faSopenharmony_ci dev->state = DS_BUSY; 1688f9f848faSopenharmony_ci else 1689f9f848faSopenharmony_ci dev->state = DS_ATTACHED; 1690f9f848faSopenharmony_ci dev->flags &= ~DF_DONENOMATCH; 1691f9f848faSopenharmony_ci //EVENTHANDLER_INVOKE(device_attach, dev); 1692f9f848faSopenharmony_ci //devadded(dev); 1693f9f848faSopenharmony_ci PDEBUG(("-")); 1694f9f848faSopenharmony_ci return (0); 1695f9f848faSopenharmony_ci} 1696f9f848faSopenharmony_ci 1697f9f848faSopenharmony_ci/** 1698f9f848faSopenharmony_ci * @brief Probe a device, and return this status. 1699f9f848faSopenharmony_ci * 1700f9f848faSopenharmony_ci * This function is the core of the device autoconfiguration 1701f9f848faSopenharmony_ci * system. Its purpose is to select a suitable driver for a device and 1702f9f848faSopenharmony_ci * then call that driver to initialise the hardware appropriately. The 1703f9f848faSopenharmony_ci * driver is selected by calling the DEVICE_PROBE() method of a set of 1704f9f848faSopenharmony_ci * candidate drivers and then choosing the driver which returned the 1705f9f848faSopenharmony_ci * best value. This driver is then attached to the device using 1706f9f848faSopenharmony_ci * device_attach(). 1707f9f848faSopenharmony_ci * 1708f9f848faSopenharmony_ci * The set of suitable drivers is taken from the list of drivers in 1709f9f848faSopenharmony_ci * the parent device's devclass. If the device was originally created 1710f9f848faSopenharmony_ci * with a specific class name (see device_add_child()), only drivers 1711f9f848faSopenharmony_ci * with that name are probed, otherwise all drivers in the devclass 1712f9f848faSopenharmony_ci * are probed. If no drivers return successful probe values in the 1713f9f848faSopenharmony_ci * parent devclass, the search continues in the parent of that 1714f9f848faSopenharmony_ci * devclass (see devclass_get_parent()) if any. 1715f9f848faSopenharmony_ci * 1716f9f848faSopenharmony_ci * @param dev the device to initialise 1717f9f848faSopenharmony_ci * 1718f9f848faSopenharmony_ci * @retval 0 success 1719f9f848faSopenharmony_ci * @retval ENXIO no driver was found 1720f9f848faSopenharmony_ci * @retval ENOMEM memory allocation failure 1721f9f848faSopenharmony_ci * @retval non-zero some other unix error code 1722f9f848faSopenharmony_ci * @retval -1 Device already attached 1723f9f848faSopenharmony_ci */ 1724f9f848faSopenharmony_ciint 1725f9f848faSopenharmony_cidevice_probe(device_t dev) 1726f9f848faSopenharmony_ci{ 1727f9f848faSopenharmony_ci int error; 1728f9f848faSopenharmony_ci 1729f9f848faSopenharmony_ci GIANT_REQUIRED; 1730f9f848faSopenharmony_ci PDEBUG(("+")); 1731f9f848faSopenharmony_ci 1732f9f848faSopenharmony_ci if (dev->state >= DS_ALIVE && (dev->flags & DF_REBID) == 0) 1733f9f848faSopenharmony_ci return (-1); 1734f9f848faSopenharmony_ci 1735f9f848faSopenharmony_ci if (!(dev->flags & DF_ENABLED)) { 1736f9f848faSopenharmony_ci if (bootverbose && device_get_name(dev) != NULL) { 1737f9f848faSopenharmony_ci device_print_prettyname(dev); 1738f9f848faSopenharmony_ci printf("not probed (disabled)\n"); 1739f9f848faSopenharmony_ci } 1740f9f848faSopenharmony_ci return (-1); 1741f9f848faSopenharmony_ci } 1742f9f848faSopenharmony_ci if ((error = device_probe_child(dev->parent, dev)) != 0) { 1743f9f848faSopenharmony_ci if (bus_current_pass == BUS_PASS_DEFAULT && 1744f9f848faSopenharmony_ci !(dev->flags & DF_DONENOMATCH)) { 1745f9f848faSopenharmony_ci BUS_PROBE_NOMATCH(dev->parent, dev); 1746f9f848faSopenharmony_ci //devnomatch(dev); 1747f9f848faSopenharmony_ci dev->flags |= DF_DONENOMATCH; 1748f9f848faSopenharmony_ci } 1749f9f848faSopenharmony_ci return (error); 1750f9f848faSopenharmony_ci } 1751f9f848faSopenharmony_ci PDEBUG(("-")); 1752f9f848faSopenharmony_ci return (0); 1753f9f848faSopenharmony_ci} 1754f9f848faSopenharmony_ci 1755f9f848faSopenharmony_ci/** 1756f9f848faSopenharmony_ci * @brief Tells a driver to quiesce itself. 1757f9f848faSopenharmony_ci * 1758f9f848faSopenharmony_ci * This function is a wrapper around the DEVICE_QUIESCE() driver 1759f9f848faSopenharmony_ci * method. If the call to DEVICE_QUIESCE() succeeds. 1760f9f848faSopenharmony_ci * 1761f9f848faSopenharmony_ci * @param dev the device to quiesce 1762f9f848faSopenharmony_ci * 1763f9f848faSopenharmony_ci * @retval 0 success 1764f9f848faSopenharmony_ci * @retval ENXIO no driver was found 1765f9f848faSopenharmony_ci * @retval ENOMEM memory allocation failure 1766f9f848faSopenharmony_ci * @retval non-zero some other unix error code 1767f9f848faSopenharmony_ci */ 1768f9f848faSopenharmony_ciint 1769f9f848faSopenharmony_cidevice_quiesce(device_t dev) 1770f9f848faSopenharmony_ci{ 1771f9f848faSopenharmony_ci 1772f9f848faSopenharmony_ci PDEBUG(("%s", DEVICENAME(dev))); 1773f9f848faSopenharmony_ci if (dev->state == DS_BUSY) 1774f9f848faSopenharmony_ci return (EBUSY); 1775f9f848faSopenharmony_ci if (dev->state != DS_ATTACHED) 1776f9f848faSopenharmony_ci return (0); 1777f9f848faSopenharmony_ci 1778f9f848faSopenharmony_ci return (DEVICE_QUIESCE(dev)); 1779f9f848faSopenharmony_ci} 1780f9f848faSopenharmony_ci 1781f9f848faSopenharmony_ci/** 1782f9f848faSopenharmony_ci * @brief Notify a device of system shutdown 1783f9f848faSopenharmony_ci * 1784f9f848faSopenharmony_ci * This function calls the DEVICE_SHUTDOWN() driver method if the 1785f9f848faSopenharmony_ci * device currently has an attached driver. 1786f9f848faSopenharmony_ci * 1787f9f848faSopenharmony_ci * @returns the value returned by DEVICE_SHUTDOWN() 1788f9f848faSopenharmony_ci */ 1789f9f848faSopenharmony_ciint 1790f9f848faSopenharmony_cidevice_shutdown(device_t dev) 1791f9f848faSopenharmony_ci{ 1792f9f848faSopenharmony_ci if (dev->state < DS_ATTACHED) 1793f9f848faSopenharmony_ci return (0); 1794f9f848faSopenharmony_ci return (DEVICE_SHUTDOWN(dev)); 1795f9f848faSopenharmony_ci} 1796f9f848faSopenharmony_ci 1797f9f848faSopenharmony_ci// bus 1798f9f848faSopenharmony_ci// 1799f9f848faSopenharmony_ci// 1800f9f848faSopenharmony_cidevice_t 1801f9f848faSopenharmony_cibus_generic_add_child(device_t dev, u_int order, const char *name, int unit) 1802f9f848faSopenharmony_ci{ 1803f9f848faSopenharmony_ci 1804f9f848faSopenharmony_ci return (device_add_child_ordered(dev, order, name, unit)); 1805f9f848faSopenharmony_ci} 1806f9f848faSopenharmony_ci 1807f9f848faSopenharmony_ci/** 1808f9f848faSopenharmony_ci * @brief Helper function for implementing DEVICE_PROBE() 1809f9f848faSopenharmony_ci * 1810f9f848faSopenharmony_ci * This function can be used to help implement the DEVICE_PROBE() for 1811f9f848faSopenharmony_ci * a bus (i.e. a device which has other devices attached to it). It 1812f9f848faSopenharmony_ci * calls the DEVICE_IDENTIFY() method of each driver in the device's 1813f9f848faSopenharmony_ci * devclass. 1814f9f848faSopenharmony_ci */ 1815f9f848faSopenharmony_ciint 1816f9f848faSopenharmony_cibus_generic_probe(device_t dev) 1817f9f848faSopenharmony_ci{ 1818f9f848faSopenharmony_ci devclass_t dc = dev->devclass; 1819f9f848faSopenharmony_ci driverlink_t dl = NULL; 1820f9f848faSopenharmony_ci PDEBUG(("+")); 1821f9f848faSopenharmony_ci 1822f9f848faSopenharmony_ci TAILQ_FOREACH(dl, &dc->drivers, link) { 1823f9f848faSopenharmony_ci /* 1824f9f848faSopenharmony_ci * If this driver's pass is too high, then ignore it. 1825f9f848faSopenharmony_ci * For most drivers in the default pass, this will 1826f9f848faSopenharmony_ci * never be true. For early-pass drivers they will 1827f9f848faSopenharmony_ci * only call the identify routines of eligible drivers 1828f9f848faSopenharmony_ci * when this routine is called. Drivers for later 1829f9f848faSopenharmony_ci * passes should have their identify routines called 1830f9f848faSopenharmony_ci * on early-pass busses during BUS_NEW_PASS(). 1831f9f848faSopenharmony_ci */ 1832f9f848faSopenharmony_ci if (dl->pass > bus_current_pass) 1833f9f848faSopenharmony_ci continue; 1834f9f848faSopenharmony_ci DEVICE_IDENTIFY(dl->driver, dev); 1835f9f848faSopenharmony_ci } 1836f9f848faSopenharmony_ci 1837f9f848faSopenharmony_ci PDEBUG(("-")); 1838f9f848faSopenharmony_ci return (0); 1839f9f848faSopenharmony_ci} 1840f9f848faSopenharmony_ci 1841f9f848faSopenharmony_ci/** 1842f9f848faSopenharmony_ci * @brief Helper function for implementing DEVICE_ATTACH() 1843f9f848faSopenharmony_ci * 1844f9f848faSopenharmony_ci * This function can be used to help implement the DEVICE_ATTACH() for 1845f9f848faSopenharmony_ci * a bus. It calls device_probe_and_attach() for each of the device's 1846f9f848faSopenharmony_ci * children. 1847f9f848faSopenharmony_ci */ 1848f9f848faSopenharmony_ciint 1849f9f848faSopenharmony_cibus_generic_attach(device_t dev) 1850f9f848faSopenharmony_ci{ 1851f9f848faSopenharmony_ci device_t child; 1852f9f848faSopenharmony_ci 1853f9f848faSopenharmony_ci PDEBUG(("+")); 1854f9f848faSopenharmony_ci TAILQ_FOREACH(child, &dev->children, link) { 1855f9f848faSopenharmony_ci device_probe_and_attach(child); 1856f9f848faSopenharmony_ci } 1857f9f848faSopenharmony_ci PDEBUG(("-")); 1858f9f848faSopenharmony_ci return (0); 1859f9f848faSopenharmony_ci} 1860f9f848faSopenharmony_ci 1861f9f848faSopenharmony_ci/** 1862f9f848faSopenharmony_ci * @brief Helper function for implementing DEVICE_DETACH() 1863f9f848faSopenharmony_ci * 1864f9f848faSopenharmony_ci * This function can be used to help implement the DEVICE_DETACH() for 1865f9f848faSopenharmony_ci * a bus. It calls device_detach() for each of the device's 1866f9f848faSopenharmony_ci * children. 1867f9f848faSopenharmony_ci */ 1868f9f848faSopenharmony_ciint 1869f9f848faSopenharmony_cibus_generic_detach(device_t dev) 1870f9f848faSopenharmony_ci{ 1871f9f848faSopenharmony_ci device_t child; 1872f9f848faSopenharmony_ci int error; 1873f9f848faSopenharmony_ci 1874f9f848faSopenharmony_ci if (dev->state != DS_ATTACHED) 1875f9f848faSopenharmony_ci return (EBUSY); 1876f9f848faSopenharmony_ci 1877f9f848faSopenharmony_ci /* 1878f9f848faSopenharmony_ci * Detach children in the reverse order. 1879f9f848faSopenharmony_ci * See bus_generic_suspend for details. 1880f9f848faSopenharmony_ci */ 1881f9f848faSopenharmony_ci TAILQ_FOREACH_REVERSE(child, &dev->children, device_list, link) { 1882f9f848faSopenharmony_ci if ((error = device_detach(child)) != 0) 1883f9f848faSopenharmony_ci return (error); 1884f9f848faSopenharmony_ci } 1885f9f848faSopenharmony_ci 1886f9f848faSopenharmony_ci return (0); 1887f9f848faSopenharmony_ci} 1888f9f848faSopenharmony_ci 1889f9f848faSopenharmony_ci/** 1890f9f848faSopenharmony_ci * @brief Helper function for implementing DEVICE_SHUTDOWN() 1891f9f848faSopenharmony_ci * 1892f9f848faSopenharmony_ci * This function can be used to help implement the DEVICE_SHUTDOWN() 1893f9f848faSopenharmony_ci * for a bus. It calls device_shutdown() for each of the device's 1894f9f848faSopenharmony_ci * children. 1895f9f848faSopenharmony_ci */ 1896f9f848faSopenharmony_ciint 1897f9f848faSopenharmony_cibus_generic_shutdown(device_t dev) 1898f9f848faSopenharmony_ci{ 1899f9f848faSopenharmony_ci device_t child; 1900f9f848faSopenharmony_ci 1901f9f848faSopenharmony_ci /* 1902f9f848faSopenharmony_ci * Shut down children in the reverse order. 1903f9f848faSopenharmony_ci * See bus_generic_suspend for details. 1904f9f848faSopenharmony_ci */ 1905f9f848faSopenharmony_ci TAILQ_FOREACH_REVERSE(child, &dev->children, device_list, link) { 1906f9f848faSopenharmony_ci device_shutdown(child); 1907f9f848faSopenharmony_ci } 1908f9f848faSopenharmony_ci 1909f9f848faSopenharmony_ci return (0); 1910f9f848faSopenharmony_ci} 1911f9f848faSopenharmony_ci 1912f9f848faSopenharmony_ci/** 1913f9f848faSopenharmony_ci * @brief Default function for suspending a child device. 1914f9f848faSopenharmony_ci * 1915f9f848faSopenharmony_ci * This function is to be used by a bus's DEVICE_SUSPEND_CHILD(). 1916f9f848faSopenharmony_ci */ 1917f9f848faSopenharmony_ciint 1918f9f848faSopenharmony_cibus_generic_suspend_child(device_t dev, device_t child) 1919f9f848faSopenharmony_ci{ 1920f9f848faSopenharmony_ci int error; 1921f9f848faSopenharmony_ci 1922f9f848faSopenharmony_ci error = DEVICE_SUSPEND(child); 1923f9f848faSopenharmony_ci 1924f9f848faSopenharmony_ci if (error == 0) 1925f9f848faSopenharmony_ci child->flags |= DF_SUSPENDED; 1926f9f848faSopenharmony_ci 1927f9f848faSopenharmony_ci return (error); 1928f9f848faSopenharmony_ci} 1929f9f848faSopenharmony_ci 1930f9f848faSopenharmony_ci/** 1931f9f848faSopenharmony_ci * @brief Default function for resuming a child device. 1932f9f848faSopenharmony_ci * 1933f9f848faSopenharmony_ci * This function is to be used by a bus's DEVICE_RESUME_CHILD(). 1934f9f848faSopenharmony_ci */ 1935f9f848faSopenharmony_ciint 1936f9f848faSopenharmony_cibus_generic_resume_child(device_t dev, device_t child) 1937f9f848faSopenharmony_ci{ 1938f9f848faSopenharmony_ci 1939f9f848faSopenharmony_ci DEVICE_RESUME(child); 1940f9f848faSopenharmony_ci child->flags &= ~DF_SUSPENDED; 1941f9f848faSopenharmony_ci 1942f9f848faSopenharmony_ci return (0); 1943f9f848faSopenharmony_ci} 1944f9f848faSopenharmony_ci 1945f9f848faSopenharmony_ci/** 1946f9f848faSopenharmony_ci * @brief Helper function for implementing DEVICE_SUSPEND() 1947f9f848faSopenharmony_ci * 1948f9f848faSopenharmony_ci * This function can be used to help implement the DEVICE_SUSPEND() 1949f9f848faSopenharmony_ci * for a bus. It calls DEVICE_SUSPEND() for each of the device's 1950f9f848faSopenharmony_ci * children. If any call to DEVICE_SUSPEND() fails, the suspend 1951f9f848faSopenharmony_ci * operation is aborted and any devices which were suspended are 1952f9f848faSopenharmony_ci * resumed immediately by calling their DEVICE_RESUME() methods. 1953f9f848faSopenharmony_ci */ 1954f9f848faSopenharmony_ciint 1955f9f848faSopenharmony_cibus_generic_suspend(device_t dev) 1956f9f848faSopenharmony_ci{ 1957f9f848faSopenharmony_ci int error; 1958f9f848faSopenharmony_ci device_t child; 1959f9f848faSopenharmony_ci 1960f9f848faSopenharmony_ci /* 1961f9f848faSopenharmony_ci * Suspend children in the reverse order. 1962f9f848faSopenharmony_ci * For most buses all children are equal, so the order does not matter. 1963f9f848faSopenharmony_ci * Other buses, such as acpi, carefully order their child devices to 1964f9f848faSopenharmony_ci * express implicit dependencies between them. For such buses it is 1965f9f848faSopenharmony_ci * safer to bring down devices in the reverse order. 1966f9f848faSopenharmony_ci */ 1967f9f848faSopenharmony_ci TAILQ_FOREACH_REVERSE(child, &dev->children, device_list, link) { 1968f9f848faSopenharmony_ci error = BUS_SUSPEND_CHILD(dev, child); 1969f9f848faSopenharmony_ci if (error != 0) { 1970f9f848faSopenharmony_ci child = TAILQ_NEXT(child, link); 1971f9f848faSopenharmony_ci if (child != NULL) { 1972f9f848faSopenharmony_ci TAILQ_FOREACH_FROM(child, &dev->children, link) 1973f9f848faSopenharmony_ci BUS_RESUME_CHILD(dev, child); 1974f9f848faSopenharmony_ci } 1975f9f848faSopenharmony_ci return (error); 1976f9f848faSopenharmony_ci } 1977f9f848faSopenharmony_ci } 1978f9f848faSopenharmony_ci return (0); 1979f9f848faSopenharmony_ci} 1980f9f848faSopenharmony_ci 1981f9f848faSopenharmony_ci/** 1982f9f848faSopenharmony_ci * @brief Helper function for implementing DEVICE_RESUME() 1983f9f848faSopenharmony_ci * 1984f9f848faSopenharmony_ci * This function can be used to help implement the DEVICE_RESUME() for 1985f9f848faSopenharmony_ci * a bus. It calls DEVICE_RESUME() on each of the device's children. 1986f9f848faSopenharmony_ci */ 1987f9f848faSopenharmony_ciint 1988f9f848faSopenharmony_cibus_generic_resume(device_t dev) 1989f9f848faSopenharmony_ci{ 1990f9f848faSopenharmony_ci device_t child; 1991f9f848faSopenharmony_ci 1992f9f848faSopenharmony_ci TAILQ_FOREACH(child, &dev->children, link) { 1993f9f848faSopenharmony_ci BUS_RESUME_CHILD(dev, child); 1994f9f848faSopenharmony_ci /* if resume fails, there's nothing we can usefully do... */ 1995f9f848faSopenharmony_ci } 1996f9f848faSopenharmony_ci return (0); 1997f9f848faSopenharmony_ci} 1998f9f848faSopenharmony_ci 1999f9f848faSopenharmony_ci 2000f9f848faSopenharmony_ci 2001f9f848faSopenharmony_ci/** 2002f9f848faSopenharmony_ci * @brief Helper function for implementing BUS_PRINT_CHILD(). 2003f9f848faSopenharmony_ci * 2004f9f848faSopenharmony_ci * This function prints the first part of the ascii representation of 2005f9f848faSopenharmony_ci * @p child, including its name, unit and description (if any - see 2006f9f848faSopenharmony_ci * device_set_desc()). 2007f9f848faSopenharmony_ci * 2008f9f848faSopenharmony_ci * @returns the number of characters printed 2009f9f848faSopenharmony_ci */ 2010f9f848faSopenharmony_ciint 2011f9f848faSopenharmony_cibus_print_child_header(device_t dev, device_t child) 2012f9f848faSopenharmony_ci{ 2013f9f848faSopenharmony_ci int retval = 0; 2014f9f848faSopenharmony_ci 2015f9f848faSopenharmony_ci if (device_get_desc(child)) { 2016f9f848faSopenharmony_ci retval += device_printf(child, "<%s>", device_get_desc(child)); 2017f9f848faSopenharmony_ci } else { 2018f9f848faSopenharmony_ci retval += printf("%s", device_get_nameunit(child)); 2019f9f848faSopenharmony_ci } 2020f9f848faSopenharmony_ci 2021f9f848faSopenharmony_ci return (retval); 2022f9f848faSopenharmony_ci} 2023f9f848faSopenharmony_ci 2024f9f848faSopenharmony_ci/** 2025f9f848faSopenharmony_ci * @brief Helper function for implementing BUS_PRINT_CHILD(). 2026f9f848faSopenharmony_ci * 2027f9f848faSopenharmony_ci * This function prints the last part of the ascii representation of 2028f9f848faSopenharmony_ci * @p child, which consists of the string @c " on " followed by the 2029f9f848faSopenharmony_ci * name and unit of the @p dev. 2030f9f848faSopenharmony_ci * 2031f9f848faSopenharmony_ci * @returns the number of characters printed 2032f9f848faSopenharmony_ci */ 2033f9f848faSopenharmony_ciint 2034f9f848faSopenharmony_cibus_print_child_footer(device_t dev, device_t child) 2035f9f848faSopenharmony_ci{ 2036f9f848faSopenharmony_ci return (printf(" on %s\n", device_get_nameunit(dev))); 2037f9f848faSopenharmony_ci} 2038f9f848faSopenharmony_ci 2039f9f848faSopenharmony_ci/** 2040f9f848faSopenharmony_ci * @brief Helper function for implementing BUS_PRINT_CHILD(). 2041f9f848faSopenharmony_ci * 2042f9f848faSopenharmony_ci * This function prints out the VM domain for the given device. 2043f9f848faSopenharmony_ci * 2044f9f848faSopenharmony_ci * @returns the number of characters printed 2045f9f848faSopenharmony_ci */ 2046f9f848faSopenharmony_ciint 2047f9f848faSopenharmony_cibus_print_child_domain(device_t dev, device_t child) 2048f9f848faSopenharmony_ci{ 2049f9f848faSopenharmony_ci int domain; 2050f9f848faSopenharmony_ci 2051f9f848faSopenharmony_ci /* No domain? Don't print anything */ 2052f9f848faSopenharmony_ci if (BUS_GET_DOMAIN(dev, child, &domain) != 0) 2053f9f848faSopenharmony_ci return (0); 2054f9f848faSopenharmony_ci 2055f9f848faSopenharmony_ci return (printf(" numa-domain %d", domain)); 2056f9f848faSopenharmony_ci} 2057f9f848faSopenharmony_ci 2058f9f848faSopenharmony_ci/** 2059f9f848faSopenharmony_ci * @brief Helper function for implementing BUS_PRINT_CHILD(). 2060f9f848faSopenharmony_ci * 2061f9f848faSopenharmony_ci * This function simply calls bus_print_child_header() followed by 2062f9f848faSopenharmony_ci * bus_print_child_footer(). 2063f9f848faSopenharmony_ci * 2064f9f848faSopenharmony_ci * @returns the number of characters printed 2065f9f848faSopenharmony_ci */ 2066f9f848faSopenharmony_ciint 2067f9f848faSopenharmony_cibus_generic_print_child(device_t dev, device_t child) 2068f9f848faSopenharmony_ci{ 2069f9f848faSopenharmony_ci int retval = 0; 2070f9f848faSopenharmony_ci 2071f9f848faSopenharmony_ci retval += bus_print_child_header(dev, child); 2072f9f848faSopenharmony_ci retval += bus_print_child_domain(dev, child); 2073f9f848faSopenharmony_ci retval += bus_print_child_footer(dev, child); 2074f9f848faSopenharmony_ci 2075f9f848faSopenharmony_ci return (retval); 2076f9f848faSopenharmony_ci} 2077f9f848faSopenharmony_ci 2078f9f848faSopenharmony_ci/** 2079f9f848faSopenharmony_ci * @brief Helper function for implementing BUS_DRIVER_ADDED(). 2080f9f848faSopenharmony_ci * 2081f9f848faSopenharmony_ci * This implementation of BUS_DRIVER_ADDED() simply calls the driver's 2082f9f848faSopenharmony_ci * DEVICE_IDENTIFY() method to allow it to add new children to the bus 2083f9f848faSopenharmony_ci * and then calls device_probe_and_attach() for each unattached child. 2084f9f848faSopenharmony_ci */ 2085f9f848faSopenharmony_civoid 2086f9f848faSopenharmony_cibus_generic_driver_added(device_t dev, driver_t *driver) 2087f9f848faSopenharmony_ci{ 2088f9f848faSopenharmony_ci device_t child; 2089f9f848faSopenharmony_ci PDEBUG(("+")); 2090f9f848faSopenharmony_ci 2091f9f848faSopenharmony_ci DEVICE_IDENTIFY(driver, dev); 2092f9f848faSopenharmony_ci PDEBUG(("dev->children %p", dev->children)); 2093f9f848faSopenharmony_ci TAILQ_FOREACH(child, &dev->children, link) { 2094f9f848faSopenharmony_ci if (child->state == DS_NOTPRESENT || 2095f9f848faSopenharmony_ci (child->flags & DF_REBID)) 2096f9f848faSopenharmony_ci device_probe_and_attach(child); 2097f9f848faSopenharmony_ci } 2098f9f848faSopenharmony_ci PDEBUG(("-")); 2099f9f848faSopenharmony_ci} 2100f9f848faSopenharmony_ci 2101f9f848faSopenharmony_ci/** 2102f9f848faSopenharmony_ci * @brief Helper function for implementing BUS_NEW_PASS(). 2103f9f848faSopenharmony_ci * 2104f9f848faSopenharmony_ci * This implementing of BUS_NEW_PASS() first calls the identify 2105f9f848faSopenharmony_ci * routines for any drivers that probe at the current pass. Then it 2106f9f848faSopenharmony_ci * walks the list of devices for this bus. If a device is already 2107f9f848faSopenharmony_ci * attached, then it calls BUS_NEW_PASS() on that device. If the 2108f9f848faSopenharmony_ci * device is not already attached, it attempts to attach a driver to 2109f9f848faSopenharmony_ci * it. 2110f9f848faSopenharmony_ci */ 2111f9f848faSopenharmony_civoid 2112f9f848faSopenharmony_cibus_generic_new_pass(device_t dev) 2113f9f848faSopenharmony_ci{ 2114f9f848faSopenharmony_ci driverlink_t dl = NULL; 2115f9f848faSopenharmony_ci devclass_t dc; 2116f9f848faSopenharmony_ci device_t child; 2117f9f848faSopenharmony_ci 2118f9f848faSopenharmony_ci dc = dev->devclass; 2119f9f848faSopenharmony_ci TAILQ_FOREACH(dl, &dc->drivers, link) { 2120f9f848faSopenharmony_ci if (dl->pass == bus_current_pass) 2121f9f848faSopenharmony_ci DEVICE_IDENTIFY(dl->driver, dev); 2122f9f848faSopenharmony_ci } 2123f9f848faSopenharmony_ci TAILQ_FOREACH(child, &dev->children, link) { 2124f9f848faSopenharmony_ci if (child->state >= DS_ATTACHED) 2125f9f848faSopenharmony_ci BUS_NEW_PASS(child); 2126f9f848faSopenharmony_ci else if (child->state == DS_NOTPRESENT) 2127f9f848faSopenharmony_ci device_probe_and_attach(child); 2128f9f848faSopenharmony_ci } 2129f9f848faSopenharmony_ci} 2130f9f848faSopenharmony_ci 2131f9f848faSopenharmony_ci// delete resouce and intr 2132f9f848faSopenharmony_ci 2133f9f848faSopenharmony_ci/** 2134f9f848faSopenharmony_ci * @brief Helper function for implementing BUS_CHILD_PRESENT(). 2135f9f848faSopenharmony_ci * 2136f9f848faSopenharmony_ci * This simple implementation of BUS_CHILD_PRESENT() simply calls the 2137f9f848faSopenharmony_ci * BUS_CHILD_PRESENT() method of the parent of @p dev. 2138f9f848faSopenharmony_ci */ 2139f9f848faSopenharmony_ciint 2140f9f848faSopenharmony_cibus_generic_child_present(device_t dev, device_t child) 2141f9f848faSopenharmony_ci{ 2142f9f848faSopenharmony_ci return (BUS_CHILD_PRESENT(device_get_parent(dev), dev)); 2143f9f848faSopenharmony_ci} 2144f9f848faSopenharmony_ci 2145f9f848faSopenharmony_ciint 2146f9f848faSopenharmony_cibus_generic_get_domain(device_t dev, device_t child, int *domain) 2147f9f848faSopenharmony_ci{ 2148f9f848faSopenharmony_ci 2149f9f848faSopenharmony_ci if (dev->parent) 2150f9f848faSopenharmony_ci return (BUS_GET_DOMAIN(dev->parent, dev, domain)); 2151f9f848faSopenharmony_ci 2152f9f848faSopenharmony_ci return (ENOENT); 2153f9f848faSopenharmony_ci} 2154f9f848faSopenharmony_ci 2155f9f848faSopenharmony_ci/** 2156f9f848faSopenharmony_ci * @brief Helper function for implementing BUS_RESCAN(). 2157f9f848faSopenharmony_ci * 2158f9f848faSopenharmony_ci * This null implementation of BUS_RESCAN() always fails to indicate 2159f9f848faSopenharmony_ci * the bus does not support rescanning. 2160f9f848faSopenharmony_ci */ 2161f9f848faSopenharmony_ciint 2162f9f848faSopenharmony_cibus_null_rescan(device_t dev) 2163f9f848faSopenharmony_ci{ 2164f9f848faSopenharmony_ci 2165f9f848faSopenharmony_ci return (ENXIO); 2166f9f848faSopenharmony_ci} 2167f9f848faSopenharmony_ci 2168f9f848faSopenharmony_ci/** 2169f9f848faSopenharmony_ci * @brief Wrapper function for BUS_CHILD_PRESENT(). 2170f9f848faSopenharmony_ci * 2171f9f848faSopenharmony_ci * This function simply calls the BUS_CHILD_PRESENT() method of the 2172f9f848faSopenharmony_ci * parent of @p dev. 2173f9f848faSopenharmony_ci */ 2174f9f848faSopenharmony_ciint 2175f9f848faSopenharmony_cibus_child_present(device_t child) 2176f9f848faSopenharmony_ci{ 2177f9f848faSopenharmony_ci return (BUS_CHILD_PRESENT(device_get_parent(child), child)); 2178f9f848faSopenharmony_ci} 2179f9f848faSopenharmony_ci 2180f9f848faSopenharmony_ci/** 2181f9f848faSopenharmony_ci * @brief Wrapper function for BUS_GET_DOMAIN(). 2182f9f848faSopenharmony_ci * 2183f9f848faSopenharmony_ci * This function simply calls the BUS_GET_DOMAIN() method of the 2184f9f848faSopenharmony_ci * parent of @p dev. 2185f9f848faSopenharmony_ci */ 2186f9f848faSopenharmony_ciint 2187f9f848faSopenharmony_cibus_get_domain(device_t dev, int *domain) 2188f9f848faSopenharmony_ci{ 2189f9f848faSopenharmony_ci return (BUS_GET_DOMAIN(device_get_parent(dev), dev, domain)); 2190f9f848faSopenharmony_ci} 2191f9f848faSopenharmony_ci 2192f9f848faSopenharmony_ciint 2193f9f848faSopenharmony_cibus_data_generation_check(int generation) 2194f9f848faSopenharmony_ci{ 2195f9f848faSopenharmony_ci if (generation != bus_data_generation) 2196f9f848faSopenharmony_ci return (1); 2197f9f848faSopenharmony_ci 2198f9f848faSopenharmony_ci /* XXX generate optimised lists here? */ 2199f9f848faSopenharmony_ci return (0); 2200f9f848faSopenharmony_ci} 2201f9f848faSopenharmony_ci 2202f9f848faSopenharmony_civoid 2203f9f848faSopenharmony_cibus_data_generation_update(void) 2204f9f848faSopenharmony_ci{ 2205f9f848faSopenharmony_ci bus_data_generation++; 2206f9f848faSopenharmony_ci} 2207f9f848faSopenharmony_ci 2208f9f848faSopenharmony_ci/** 2209f9f848faSopenharmony_ci * @brief Print the name of the device followed by a colon and a space 2210f9f848faSopenharmony_ci * 2211f9f848faSopenharmony_ci * @returns the number of characters printed 2212f9f848faSopenharmony_ci */ 2213f9f848faSopenharmony_ciint 2214f9f848faSopenharmony_cidevice_print_prettyname(device_t dev) 2215f9f848faSopenharmony_ci{ 2216f9f848faSopenharmony_ci const char *name = device_get_name(dev); 2217f9f848faSopenharmony_ci 2218f9f848faSopenharmony_ci if (name == NULL) 2219f9f848faSopenharmony_ci return (printf("unknown: ")); 2220f9f848faSopenharmony_ci return (printf("%s%d: ", name, device_get_unit(dev))); 2221f9f848faSopenharmony_ci} 2222f9f848faSopenharmony_ci 2223f9f848faSopenharmony_ci/** 2224f9f848faSopenharmony_ci * @brief Return the device's unit number. 2225f9f848faSopenharmony_ci */ 2226f9f848faSopenharmony_ciint 2227f9f848faSopenharmony_cidevice_get_unit(device_t dev) 2228f9f848faSopenharmony_ci{ 2229f9f848faSopenharmony_ci return (dev->unit); 2230f9f848faSopenharmony_ci} 2231f9f848faSopenharmony_ci 2232f9f848faSopenharmony_ci/** 2233f9f848faSopenharmony_ci * @internal 2234f9f848faSopenharmony_ci */ 2235f9f848faSopenharmony_cistatic driverlink_t 2236f9f848faSopenharmony_cifirst_matching_driver(devclass_t dc, device_t dev) 2237f9f848faSopenharmony_ci{ 2238f9f848faSopenharmony_ci if (dev->devclass) 2239f9f848faSopenharmony_ci return (devclass_find_driver_internal(dc, dev->devclass->name)); 2240f9f848faSopenharmony_ci return (TAILQ_FIRST(&dc->drivers)); 2241f9f848faSopenharmony_ci} 2242f9f848faSopenharmony_ci 2243f9f848faSopenharmony_ci/** 2244f9f848faSopenharmony_ci * @internal 2245f9f848faSopenharmony_ci */ 2246f9f848faSopenharmony_cistatic driverlink_t 2247f9f848faSopenharmony_cinext_matching_driver(devclass_t dc, device_t dev, driverlink_t last) 2248f9f848faSopenharmony_ci{ 2249f9f848faSopenharmony_ci if (dev->devclass) { 2250f9f848faSopenharmony_ci driverlink_t dl; 2251f9f848faSopenharmony_ci for (dl = TAILQ_NEXT(last, link); dl; dl = TAILQ_NEXT(dl, link)) 2252f9f848faSopenharmony_ci if (!strcmp(dev->devclass->name, dl->driver->name)) 2253f9f848faSopenharmony_ci return (dl); 2254f9f848faSopenharmony_ci return (NULL); 2255f9f848faSopenharmony_ci } 2256f9f848faSopenharmony_ci return (TAILQ_NEXT(last, link)); 2257f9f848faSopenharmony_ci} 2258f9f848faSopenharmony_ci 2259f9f848faSopenharmony_ci 2260f9f848faSopenharmony_ci/** 2261f9f848faSopenharmony_ci * @brief Set the devclass of a device 2262f9f848faSopenharmony_ci * @see devclass_add_device(). 2263f9f848faSopenharmony_ci */ 2264f9f848faSopenharmony_ciint 2265f9f848faSopenharmony_cidevice_set_devclass(device_t dev, const char *classname) 2266f9f848faSopenharmony_ci{ 2267f9f848faSopenharmony_ci devclass_t dc; 2268f9f848faSopenharmony_ci int error; 2269f9f848faSopenharmony_ci 2270f9f848faSopenharmony_ci if (!classname) { 2271f9f848faSopenharmony_ci if (dev->devclass) 2272f9f848faSopenharmony_ci devclass_delete_device(dev->devclass, dev); 2273f9f848faSopenharmony_ci return (0); 2274f9f848faSopenharmony_ci } 2275f9f848faSopenharmony_ci 2276f9f848faSopenharmony_ci if (dev->devclass) { 2277f9f848faSopenharmony_ci printf("device_set_devclass: device class already set\n"); 2278f9f848faSopenharmony_ci return (EINVAL); 2279f9f848faSopenharmony_ci } 2280f9f848faSopenharmony_ci 2281f9f848faSopenharmony_ci dc = devclass_find_internal(classname, NULL, TRUE); 2282f9f848faSopenharmony_ci if (!dc) 2283f9f848faSopenharmony_ci return (ENOMEM); 2284f9f848faSopenharmony_ci 2285f9f848faSopenharmony_ci error = devclass_add_device(dc, dev); 2286f9f848faSopenharmony_ci 2287f9f848faSopenharmony_ci bus_data_generation_update(); 2288f9f848faSopenharmony_ci return (error); 2289f9f848faSopenharmony_ci} 2290f9f848faSopenharmony_ci 2291f9f848faSopenharmony_ci/** 2292f9f848faSopenharmony_ci * @brief Detach a driver from a device 2293f9f848faSopenharmony_ci * 2294f9f848faSopenharmony_ci * This function is a wrapper around the DEVICE_DETACH() driver 2295f9f848faSopenharmony_ci * method. If the call to DEVICE_DETACH() succeeds, it calls 2296f9f848faSopenharmony_ci * BUS_CHILD_DETACHED() for the parent of @p dev, queues a 2297f9f848faSopenharmony_ci * notification event for user-based device management services and 2298f9f848faSopenharmony_ci * cleans up the device's sysctl tree. 2299f9f848faSopenharmony_ci * 2300f9f848faSopenharmony_ci * @param dev the device to un-initialise 2301f9f848faSopenharmony_ci * 2302f9f848faSopenharmony_ci * @retval 0 success 2303f9f848faSopenharmony_ci * @retval ENXIO no driver was found 2304f9f848faSopenharmony_ci * @retval ENOMEM memory allocation failure 2305f9f848faSopenharmony_ci * @retval non-zero some other unix error code 2306f9f848faSopenharmony_ci */ 2307f9f848faSopenharmony_ciint 2308f9f848faSopenharmony_cidevice_detach(device_t dev) 2309f9f848faSopenharmony_ci{ 2310f9f848faSopenharmony_ci int error; 2311f9f848faSopenharmony_ci 2312f9f848faSopenharmony_ci GIANT_REQUIRED; 2313f9f848faSopenharmony_ci 2314f9f848faSopenharmony_ci PDEBUG(("%s", DEVICENAME(dev))); 2315f9f848faSopenharmony_ci if (dev->state == DS_BUSY) 2316f9f848faSopenharmony_ci return (EBUSY); 2317f9f848faSopenharmony_ci if (dev->state == DS_ATTACHING) { 2318f9f848faSopenharmony_ci device_printf(dev, "device in attaching state! Deferring detach.\n"); 2319f9f848faSopenharmony_ci return (EBUSY); 2320f9f848faSopenharmony_ci } 2321f9f848faSopenharmony_ci if (dev->state != DS_ATTACHED) 2322f9f848faSopenharmony_ci return (0); 2323f9f848faSopenharmony_ci 2324f9f848faSopenharmony_ci if ((error = DEVICE_DETACH(dev)) != 0) { 2325f9f848faSopenharmony_ci return (error); 2326f9f848faSopenharmony_ci } 2327f9f848faSopenharmony_ci 2328f9f848faSopenharmony_ci if (!device_is_quiet(dev)) 2329f9f848faSopenharmony_ci device_printf(dev, "detached\n"); 2330f9f848faSopenharmony_ci if (dev->parent) { 2331f9f848faSopenharmony_ci PDEBUG(("BUS_CHILD_DETACHED %s", DEVICENAME(dev->parent))); 2332f9f848faSopenharmony_ci BUS_CHILD_DETACHED(dev->parent, dev); 2333f9f848faSopenharmony_ci } 2334f9f848faSopenharmony_ci 2335f9f848faSopenharmony_ci if (!(dev->flags & DF_FIXEDCLASS)) { 2336f9f848faSopenharmony_ci PDEBUG(("devclass_delete_device")); 2337f9f848faSopenharmony_ci devclass_delete_device(dev->devclass, dev); 2338f9f848faSopenharmony_ci } 2339f9f848faSopenharmony_ci 2340f9f848faSopenharmony_ci device_verbose(dev); 2341f9f848faSopenharmony_ci dev->state = DS_NOTPRESENT; 2342f9f848faSopenharmony_ci (void)device_set_driver(dev, NULL); 2343f9f848faSopenharmony_ci 2344f9f848faSopenharmony_ci return (0); 2345f9f848faSopenharmony_ci} 2346f9f848faSopenharmony_ci 2347f9f848faSopenharmony_ci/** 2348f9f848faSopenharmony_ci * @brief Return the parent of a device 2349f9f848faSopenharmony_ci */ 2350f9f848faSopenharmony_cidevice_t 2351f9f848faSopenharmony_cidevice_get_parent(device_t dev) 2352f9f848faSopenharmony_ci{ 2353f9f848faSopenharmony_ci return (dev->parent); 2354f9f848faSopenharmony_ci} 2355f9f848faSopenharmony_ci 2356f9f848faSopenharmony_ci/** 2357f9f848faSopenharmony_ci * @brief Print the name of the device followed by a colon, a space 2358f9f848faSopenharmony_ci * and the result of calling vprintf() with the value of @p fmt and 2359f9f848faSopenharmony_ci * the following arguments. 2360f9f848faSopenharmony_ci * 2361f9f848faSopenharmony_ci * @returns the number of characters printed 2362f9f848faSopenharmony_ci */ 2363f9f848faSopenharmony_ciint 2364f9f848faSopenharmony_cidevice_printf(device_t dev, const char * fmt, ...) 2365f9f848faSopenharmony_ci{ 2366f9f848faSopenharmony_ci va_list ap; 2367f9f848faSopenharmony_ci int retval; 2368f9f848faSopenharmony_ci 2369f9f848faSopenharmony_ci retval = device_print_prettyname(dev); 2370f9f848faSopenharmony_ci va_start(ap, fmt); 2371f9f848faSopenharmony_ci retval += vprintf(fmt, ap); 2372f9f848faSopenharmony_ci va_end(ap); 2373f9f848faSopenharmony_ci return (retval); 2374f9f848faSopenharmony_ci} 2375f9f848faSopenharmony_ci 2376f9f848faSopenharmony_ci/** 2377f9f848faSopenharmony_ci * @brief Set the driver of a device 2378f9f848faSopenharmony_ci * 2379f9f848faSopenharmony_ci * @retval 0 success 2380f9f848faSopenharmony_ci * @retval EBUSY the device already has a driver attached 2381f9f848faSopenharmony_ci * @retval ENOMEM a memory allocation failure occurred 2382f9f848faSopenharmony_ci */ 2383f9f848faSopenharmony_ciint 2384f9f848faSopenharmony_cidevice_set_driver(device_t dev, driver_t *driver) 2385f9f848faSopenharmony_ci{ 2386f9f848faSopenharmony_ci if (dev->state >= DS_ATTACHED) 2387f9f848faSopenharmony_ci return (EBUSY); 2388f9f848faSopenharmony_ci 2389f9f848faSopenharmony_ci if (dev->driver == driver) 2390f9f848faSopenharmony_ci return (0); 2391f9f848faSopenharmony_ci 2392f9f848faSopenharmony_ci if (dev->softc && !(dev->flags & DF_EXTERNALSOFTC)) { 2393f9f848faSopenharmony_ci bsd_free(dev->softc, M_BUS_SC); 2394f9f848faSopenharmony_ci dev->softc = NULL; 2395f9f848faSopenharmony_ci } 2396f9f848faSopenharmony_ci device_set_desc(dev, NULL); 2397f9f848faSopenharmony_ci kobj_delete((kobj_t) dev, NULL); 2398f9f848faSopenharmony_ci dev->driver = driver; 2399f9f848faSopenharmony_ci if (driver) { 2400f9f848faSopenharmony_ci kobj_init((kobj_t) dev, (kobj_class_t) driver); 2401f9f848faSopenharmony_ci if (!(dev->flags & DF_EXTERNALSOFTC) && driver->size > 0) { 2402f9f848faSopenharmony_ci dev->softc = bsd_malloc(driver->size, M_BUS_SC, 2403f9f848faSopenharmony_ci M_NOWAIT | M_ZERO); 2404f9f848faSopenharmony_ci if (!dev->softc) { 2405f9f848faSopenharmony_ci kobj_delete((kobj_t) dev, NULL); 2406f9f848faSopenharmony_ci kobj_init((kobj_t) dev, &null_class); 2407f9f848faSopenharmony_ci dev->driver = NULL; 2408f9f848faSopenharmony_ci return (ENOMEM); 2409f9f848faSopenharmony_ci } 2410f9f848faSopenharmony_ci } 2411f9f848faSopenharmony_ci } else { 2412f9f848faSopenharmony_ci kobj_init((kobj_t) dev, &null_class); 2413f9f848faSopenharmony_ci } 2414f9f848faSopenharmony_ci 2415f9f848faSopenharmony_ci bus_data_generation_update(); 2416f9f848faSopenharmony_ci return (0); 2417f9f848faSopenharmony_ci} 2418f9f848faSopenharmony_ci 2419f9f848faSopenharmony_ci/** 2420f9f848faSopenharmony_ci * @internal 2421f9f848faSopenharmony_ci */ 2422f9f848faSopenharmony_ciint 2423f9f848faSopenharmony_cidevice_probe_child(device_t dev, device_t child) 2424f9f848faSopenharmony_ci{ 2425f9f848faSopenharmony_ci devclass_t dc; 2426f9f848faSopenharmony_ci driverlink_t best = NULL; 2427f9f848faSopenharmony_ci driverlink_t dl = NULL; 2428f9f848faSopenharmony_ci int result, pri = 0; 2429f9f848faSopenharmony_ci int hasclass = (child->devclass != NULL); 2430f9f848faSopenharmony_ci 2431f9f848faSopenharmony_ci GIANT_REQUIRED; 2432f9f848faSopenharmony_ci 2433f9f848faSopenharmony_ci dc = dev->devclass; 2434f9f848faSopenharmony_ci if (!dc) 2435f9f848faSopenharmony_ci panic("device_probe_child: parent device has no devclass"); 2436f9f848faSopenharmony_ci 2437f9f848faSopenharmony_ci /* 2438f9f848faSopenharmony_ci * If the state is already probed, then return. However, don't 2439f9f848faSopenharmony_ci * return if we can rebid this object. 2440f9f848faSopenharmony_ci */ 2441f9f848faSopenharmony_ci if (child->state == DS_ALIVE && (child->flags & DF_REBID) == 0) 2442f9f848faSopenharmony_ci return (0); 2443f9f848faSopenharmony_ci 2444f9f848faSopenharmony_ci for (; dc; dc = dc->parent) { 2445f9f848faSopenharmony_ci for (dl = first_matching_driver(dc, child); 2446f9f848faSopenharmony_ci dl; 2447f9f848faSopenharmony_ci dl = next_matching_driver(dc, child, dl)) { 2448f9f848faSopenharmony_ci /* If this driver's pass is too high, then ignore it. */ 2449f9f848faSopenharmony_ci if (dl->pass > bus_current_pass) 2450f9f848faSopenharmony_ci continue; 2451f9f848faSopenharmony_ci 2452f9f848faSopenharmony_ci PDEBUG(("Trying %s", DRIVERNAME(dl->driver))); 2453f9f848faSopenharmony_ci result = device_set_driver(child, dl->driver); 2454f9f848faSopenharmony_ci if (result == ENOMEM) 2455f9f848faSopenharmony_ci return (result); 2456f9f848faSopenharmony_ci else if (result != 0) 2457f9f848faSopenharmony_ci continue; 2458f9f848faSopenharmony_ci if (!hasclass) { 2459f9f848faSopenharmony_ci if (device_set_devclass(child, 2460f9f848faSopenharmony_ci dl->driver->name) != 0) { 2461f9f848faSopenharmony_ci char const * devname = 2462f9f848faSopenharmony_ci device_get_name(child); 2463f9f848faSopenharmony_ci if (devname == NULL) 2464f9f848faSopenharmony_ci devname = "(unknown)"; 2465f9f848faSopenharmony_ci printf("driver bug: Unable to set " 2466f9f848faSopenharmony_ci "devclass (class: %s " 2467f9f848faSopenharmony_ci "devname: %s)\n", 2468f9f848faSopenharmony_ci dl->driver->name, 2469f9f848faSopenharmony_ci devname); 2470f9f848faSopenharmony_ci (void)device_set_driver(child, NULL); 2471f9f848faSopenharmony_ci continue; 2472f9f848faSopenharmony_ci } 2473f9f848faSopenharmony_ci } 2474f9f848faSopenharmony_ci 2475f9f848faSopenharmony_ci /* Fetch any flags for the device before probing. */ 2476f9f848faSopenharmony_ci // resource_int_value(dl->driver->name, child->unit, 2477f9f848faSopenharmony_ci // "flags", &child->devflags); 2478f9f848faSopenharmony_ci PDEBUG(("start DEVICE_PROBE")); 2479f9f848faSopenharmony_ci result = DEVICE_PROBE(child); 2480f9f848faSopenharmony_ci 2481f9f848faSopenharmony_ci /* Reset flags and devclass before the next probe. */ 2482f9f848faSopenharmony_ci child->devflags = 0; 2483f9f848faSopenharmony_ci if (!hasclass) 2484f9f848faSopenharmony_ci (void)device_set_devclass(child, NULL); 2485f9f848faSopenharmony_ci 2486f9f848faSopenharmony_ci /* 2487f9f848faSopenharmony_ci * If the driver returns SUCCESS, there can be 2488f9f848faSopenharmony_ci * no higher match for this device. 2489f9f848faSopenharmony_ci */ 2490f9f848faSopenharmony_ci if (result == 0) { 2491f9f848faSopenharmony_ci best = dl; 2492f9f848faSopenharmony_ci pri = 0; 2493f9f848faSopenharmony_ci break; 2494f9f848faSopenharmony_ci } 2495f9f848faSopenharmony_ci 2496f9f848faSopenharmony_ci /* 2497f9f848faSopenharmony_ci * Reset DF_QUIET in case this driver doesn't 2498f9f848faSopenharmony_ci * end up as the best driver. 2499f9f848faSopenharmony_ci */ 2500f9f848faSopenharmony_ci device_verbose(child); 2501f9f848faSopenharmony_ci 2502f9f848faSopenharmony_ci PDEBUG(("probe result: %d", result)); 2503f9f848faSopenharmony_ci /* 2504f9f848faSopenharmony_ci * Probes that return BUS_PROBE_NOWILDCARD or lower 2505f9f848faSopenharmony_ci * only match on devices whose driver was explicitly 2506f9f848faSopenharmony_ci * specified. 2507f9f848faSopenharmony_ci */ 2508f9f848faSopenharmony_ci if (result <= BUS_PROBE_NOWILDCARD && 2509f9f848faSopenharmony_ci !(child->flags & DF_FIXEDCLASS)) { 2510f9f848faSopenharmony_ci result = ENXIO; 2511f9f848faSopenharmony_ci } 2512f9f848faSopenharmony_ci 2513f9f848faSopenharmony_ci /* 2514f9f848faSopenharmony_ci * The driver returned an error so it 2515f9f848faSopenharmony_ci * certainly doesn't match. 2516f9f848faSopenharmony_ci */ 2517f9f848faSopenharmony_ci if (result > 0) { 2518f9f848faSopenharmony_ci (void)device_set_driver(child, NULL); 2519f9f848faSopenharmony_ci continue; 2520f9f848faSopenharmony_ci } 2521f9f848faSopenharmony_ci 2522f9f848faSopenharmony_ci /* 2523f9f848faSopenharmony_ci * A priority lower than SUCCESS, remember the 2524f9f848faSopenharmony_ci * best matching driver. Initialise the value 2525f9f848faSopenharmony_ci * of pri for the first match. 2526f9f848faSopenharmony_ci */ 2527f9f848faSopenharmony_ci if (best == NULL || result > pri) { 2528f9f848faSopenharmony_ci best = dl; 2529f9f848faSopenharmony_ci pri = result; 2530f9f848faSopenharmony_ci continue; 2531f9f848faSopenharmony_ci } 2532f9f848faSopenharmony_ci } 2533f9f848faSopenharmony_ci /* 2534f9f848faSopenharmony_ci * If we have an unambiguous match in this devclass, 2535f9f848faSopenharmony_ci * don't look in the parent. 2536f9f848faSopenharmony_ci */ 2537f9f848faSopenharmony_ci if (best && pri == 0) 2538f9f848faSopenharmony_ci break; 2539f9f848faSopenharmony_ci } 2540f9f848faSopenharmony_ci 2541f9f848faSopenharmony_ci /* 2542f9f848faSopenharmony_ci * If we found a driver, change state and initialise the devclass. 2543f9f848faSopenharmony_ci */ 2544f9f848faSopenharmony_ci /* XXX What happens if we rebid and got no best? */ 2545f9f848faSopenharmony_ci if (best) { 2546f9f848faSopenharmony_ci PDEBUG(("in best")); 2547f9f848faSopenharmony_ci /* 2548f9f848faSopenharmony_ci * If this device was attached, and we were asked to 2549f9f848faSopenharmony_ci * rescan, and it is a different driver, then we have 2550f9f848faSopenharmony_ci * to detach the old driver and reattach this new one. 2551f9f848faSopenharmony_ci * Note, we don't have to check for DF_REBID here 2552f9f848faSopenharmony_ci * because if the state is > DS_ALIVE, we know it must 2553f9f848faSopenharmony_ci * be. 2554f9f848faSopenharmony_ci * 2555f9f848faSopenharmony_ci * This assumes that all DF_REBID drivers can have 2556f9f848faSopenharmony_ci * their probe routine called at any time and that 2557f9f848faSopenharmony_ci * they are idempotent as well as completely benign in 2558f9f848faSopenharmony_ci * normal operations. 2559f9f848faSopenharmony_ci * 2560f9f848faSopenharmony_ci * We also have to make sure that the detach 2561f9f848faSopenharmony_ci * succeeded, otherwise we fail the operation (or 2562f9f848faSopenharmony_ci * maybe it should just fail silently? I'm torn). 2563f9f848faSopenharmony_ci */ 2564f9f848faSopenharmony_ci if (child->state > DS_ALIVE && best->driver != child->driver) 2565f9f848faSopenharmony_ci if ((result = device_detach(dev)) != 0) 2566f9f848faSopenharmony_ci return (result); 2567f9f848faSopenharmony_ci 2568f9f848faSopenharmony_ci /* Set the winning driver, devclass, and flags. */ 2569f9f848faSopenharmony_ci if (!child->devclass) { 2570f9f848faSopenharmony_ci result = device_set_devclass(child, best->driver->name); 2571f9f848faSopenharmony_ci if (result != 0) 2572f9f848faSopenharmony_ci return (result); 2573f9f848faSopenharmony_ci } 2574f9f848faSopenharmony_ci result = device_set_driver(child, best->driver); 2575f9f848faSopenharmony_ci if (result != 0) 2576f9f848faSopenharmony_ci return (result); 2577f9f848faSopenharmony_ci // resource_int_value(best->driver->name, child->unit, 2578f9f848faSopenharmony_ci // "flags", &child->devflags); 2579f9f848faSopenharmony_ci 2580f9f848faSopenharmony_ci if (pri < 0) { 2581f9f848faSopenharmony_ci /* 2582f9f848faSopenharmony_ci * A bit bogus. Call the probe method again to make 2583f9f848faSopenharmony_ci * sure that we have the right description. 2584f9f848faSopenharmony_ci */ 2585f9f848faSopenharmony_ci DEVICE_PROBE(child); 2586f9f848faSopenharmony_ci#if 0 2587f9f848faSopenharmony_ci child->flags |= DF_REBID; 2588f9f848faSopenharmony_ci#endif 2589f9f848faSopenharmony_ci } else 2590f9f848faSopenharmony_ci child->flags &= ~DF_REBID; 2591f9f848faSopenharmony_ci child->state = DS_ALIVE; 2592f9f848faSopenharmony_ci 2593f9f848faSopenharmony_ci bus_data_generation_update(); 2594f9f848faSopenharmony_ci PDEBUG(("-")); 2595f9f848faSopenharmony_ci return (0); 2596f9f848faSopenharmony_ci } 2597f9f848faSopenharmony_ci 2598f9f848faSopenharmony_ci PDEBUG(("ENXIO -")); 2599f9f848faSopenharmony_ci return (ENXIO); 2600f9f848faSopenharmony_ci} 2601f9f848faSopenharmony_ci 2602f9f848faSopenharmony_ci 2603f9f848faSopenharmony_ci/** 2604f9f848faSopenharmony_ci * @brief Return the current devclass for the device or @c NULL if 2605f9f848faSopenharmony_ci * there is none. 2606f9f848faSopenharmony_ci */ 2607f9f848faSopenharmony_cidevclass_t 2608f9f848faSopenharmony_cidevice_get_devclass(device_t dev) 2609f9f848faSopenharmony_ci{ 2610f9f848faSopenharmony_ci return (dev->devclass); 2611f9f848faSopenharmony_ci} 2612f9f848faSopenharmony_ci 2613f9f848faSopenharmony_ci/** 2614f9f848faSopenharmony_ci * @brief Initialise a resource list. 2615f9f848faSopenharmony_ci * 2616f9f848faSopenharmony_ci * @param rl the resource list to initialise 2617f9f848faSopenharmony_ci */ 2618f9f848faSopenharmony_civoid 2619f9f848faSopenharmony_ciresource_list_init(struct resource_list *rl) 2620f9f848faSopenharmony_ci{ 2621f9f848faSopenharmony_ci STAILQ_INIT(rl); 2622f9f848faSopenharmony_ci} 2623f9f848faSopenharmony_ci 2624f9f848faSopenharmony_ci/** 2625f9f848faSopenharmony_ci * @brief Reclaim memory used by a resource list. 2626f9f848faSopenharmony_ci * 2627f9f848faSopenharmony_ci * This function frees the memory for all resource entries on the list 2628f9f848faSopenharmony_ci * (if any). 2629f9f848faSopenharmony_ci * 2630f9f848faSopenharmony_ci * @param rl the resource list to free 2631f9f848faSopenharmony_ci */ 2632f9f848faSopenharmony_civoid 2633f9f848faSopenharmony_ciresource_list_free(struct resource_list *rl) 2634f9f848faSopenharmony_ci{ 2635f9f848faSopenharmony_ci struct resource_list_entry *rle; 2636f9f848faSopenharmony_ci 2637f9f848faSopenharmony_ci while ((rle = STAILQ_FIRST(rl)) != NULL) { 2638f9f848faSopenharmony_ci if (rle->res) 2639f9f848faSopenharmony_ci bsd_free(rle->res, M_BUS); 2640f9f848faSopenharmony_ci STAILQ_REMOVE_HEAD(rl, link); 2641f9f848faSopenharmony_ci bsd_free(rle, M_BUS); 2642f9f848faSopenharmony_ci } 2643f9f848faSopenharmony_ci} 2644f9f848faSopenharmony_ci 2645f9f848faSopenharmony_ci/** 2646f9f848faSopenharmony_ci * @brief Add or modify a resource entry. 2647f9f848faSopenharmony_ci * 2648f9f848faSopenharmony_ci * If an existing entry exists with the same type and rid, it will be 2649f9f848faSopenharmony_ci * modified using the given values of @p start, @p end and @p 2650f9f848faSopenharmony_ci * count. If no entry exists, a new one will be created using the 2651f9f848faSopenharmony_ci * given values. The resource list entry that matches is then returned. 2652f9f848faSopenharmony_ci * 2653f9f848faSopenharmony_ci * @param rl the resource list to edit 2654f9f848faSopenharmony_ci * @param type the resource entry type (e.g. SYS_RES_MEMORY) 2655f9f848faSopenharmony_ci * @param rid the resource identifier 2656f9f848faSopenharmony_ci * @param start the start address of the resource 2657f9f848faSopenharmony_ci * @param end the end address of the resource 2658f9f848faSopenharmony_ci * @param count XXX end-start+1 2659f9f848faSopenharmony_ci */ 2660f9f848faSopenharmony_cistruct resource_list_entry * 2661f9f848faSopenharmony_ciresource_list_add(struct resource_list *rl, int type, int rid, 2662f9f848faSopenharmony_ci rman_res_t start, rman_res_t end, rman_res_t count) 2663f9f848faSopenharmony_ci{ 2664f9f848faSopenharmony_ci struct resource_list_entry *rle; 2665f9f848faSopenharmony_ci 2666f9f848faSopenharmony_ci rle = resource_list_find(rl, type, rid); 2667f9f848faSopenharmony_ci if (!rle) { 2668f9f848faSopenharmony_ci rle = bsd_malloc(sizeof(struct resource_list_entry), M_BUS, 2669f9f848faSopenharmony_ci M_NOWAIT); 2670f9f848faSopenharmony_ci if (!rle) 2671f9f848faSopenharmony_ci panic("resource_list_add: can't record entry"); 2672f9f848faSopenharmony_ci STAILQ_INSERT_TAIL(rl, rle, link); 2673f9f848faSopenharmony_ci rle->type = type; 2674f9f848faSopenharmony_ci rle->rid = rid; 2675f9f848faSopenharmony_ci rle->res = NULL; 2676f9f848faSopenharmony_ci rle->flags = 0; 2677f9f848faSopenharmony_ci } 2678f9f848faSopenharmony_ci 2679f9f848faSopenharmony_ci if (rle->res) 2680f9f848faSopenharmony_ci panic("resource_list_add: resource entry is busy"); 2681f9f848faSopenharmony_ci 2682f9f848faSopenharmony_ci rle->res = bsd_malloc(sizeof(struct resource), M_BUS, M_NOWAIT); 2683f9f848faSopenharmony_ci if (rle->res == NULL) { 2684f9f848faSopenharmony_ci panic("resource_list_add: resource is busy"); 2685f9f848faSopenharmony_ci } 2686f9f848faSopenharmony_ci rle->res->start = start; 2687f9f848faSopenharmony_ci rle->res->end = end; 2688f9f848faSopenharmony_ci rle->res->count = count; 2689f9f848faSopenharmony_ci return (rle); 2690f9f848faSopenharmony_ci} 2691f9f848faSopenharmony_ci 2692f9f848faSopenharmony_ci/** 2693f9f848faSopenharmony_ci * @brief Find a resource entry by type and rid. 2694f9f848faSopenharmony_ci * 2695f9f848faSopenharmony_ci * @param rl the resource list to search 2696f9f848faSopenharmony_ci * @param type the resource entry type (e.g. SYS_RES_MEMORY) 2697f9f848faSopenharmony_ci * @param rid the resource identifier 2698f9f848faSopenharmony_ci * 2699f9f848faSopenharmony_ci * @returns the resource entry pointer or NULL if there is no such 2700f9f848faSopenharmony_ci * entry. 2701f9f848faSopenharmony_ci */ 2702f9f848faSopenharmony_cistruct resource_list_entry * 2703f9f848faSopenharmony_ciresource_list_find(struct resource_list *rl, int type, int rid) 2704f9f848faSopenharmony_ci{ 2705f9f848faSopenharmony_ci struct resource_list_entry *rle = NULL; 2706f9f848faSopenharmony_ci 2707f9f848faSopenharmony_ci STAILQ_FOREACH(rle, rl, link) { 2708f9f848faSopenharmony_ci if (rle->type == type && rle->rid == rid) 2709f9f848faSopenharmony_ci return (rle); 2710f9f848faSopenharmony_ci } 2711f9f848faSopenharmony_ci return (NULL); 2712f9f848faSopenharmony_ci} 2713f9f848faSopenharmony_ci 2714f9f848faSopenharmony_ci/** 2715f9f848faSopenharmony_ci * @brief Wrapper function for BUS_ALLOC_RESOURCE(). 2716f9f848faSopenharmony_ci * 2717f9f848faSopenharmony_ci * This function simply calls the BUS_ALLOC_RESOURCE() method of the 2718f9f848faSopenharmony_ci * parent of @p dev. 2719f9f848faSopenharmony_ci */ 2720f9f848faSopenharmony_cistruct resource * 2721f9f848faSopenharmony_cibus_alloc_resource(device_t dev, int type, int *rid, rman_res_t start, 2722f9f848faSopenharmony_ci rman_res_t end, rman_res_t count, u_int flags) 2723f9f848faSopenharmony_ci{ 2724f9f848faSopenharmony_ci struct resource *res = NULL; 2725f9f848faSopenharmony_ci 2726f9f848faSopenharmony_ci if (dev->parent == NULL) 2727f9f848faSopenharmony_ci return (NULL); 2728f9f848faSopenharmony_ci res = BUS_ALLOC_RESOURCE(dev->parent, dev, type, rid, start, end, 2729f9f848faSopenharmony_ci count, flags); 2730f9f848faSopenharmony_ci return (res); 2731f9f848faSopenharmony_ci} 2732f9f848faSopenharmony_ci 2733f9f848faSopenharmony_ci// root driver 2734f9f848faSopenharmony_cistatic int 2735f9f848faSopenharmony_ciroot_print_child(device_t dev, device_t child) 2736f9f848faSopenharmony_ci{ 2737f9f848faSopenharmony_ci int retval = 0; 2738f9f848faSopenharmony_ci 2739f9f848faSopenharmony_ci retval += bus_print_child_header(dev, child); 2740f9f848faSopenharmony_ci retval += printf("\n"); 2741f9f848faSopenharmony_ci 2742f9f848faSopenharmony_ci return (retval); 2743f9f848faSopenharmony_ci} 2744f9f848faSopenharmony_ci 2745f9f848faSopenharmony_cistatic kobj_method_t root_methods[] = { 2746f9f848faSopenharmony_ci /* Device interface */ 2747f9f848faSopenharmony_ci KOBJMETHOD(device_shutdown, bus_generic_shutdown), 2748f9f848faSopenharmony_ci KOBJMETHOD(device_suspend, bus_generic_suspend), 2749f9f848faSopenharmony_ci KOBJMETHOD(device_resume, bus_generic_resume), 2750f9f848faSopenharmony_ci 2751f9f848faSopenharmony_ci /* Bus interface */ 2752f9f848faSopenharmony_ci KOBJMETHOD(bus_print_child, root_print_child), 2753f9f848faSopenharmony_ci 2754f9f848faSopenharmony_ci KOBJMETHOD_END 2755f9f848faSopenharmony_ci}; 2756f9f848faSopenharmony_ci 2757f9f848faSopenharmony_cistatic driver_t root_driver = { 2758f9f848faSopenharmony_ci "root", 2759f9f848faSopenharmony_ci root_methods, 2760f9f848faSopenharmony_ci 1, /* no softc */ 2761f9f848faSopenharmony_ci}; 2762f9f848faSopenharmony_ci 2763f9f848faSopenharmony_cidevice_t root_bus; 2764f9f848faSopenharmony_cidevclass_t root_devclass; 2765f9f848faSopenharmony_ci 2766f9f848faSopenharmony_cistatic int 2767f9f848faSopenharmony_ciroot_bus_module_handler(module_t mod, int what, void* arg) 2768f9f848faSopenharmony_ci{ 2769f9f848faSopenharmony_ci PDEBUG(("+")); 2770f9f848faSopenharmony_ci switch (what) { 2771f9f848faSopenharmony_ci case MOD_LOAD: 2772f9f848faSopenharmony_ci TAILQ_INIT(&bus_data_devices); 2773f9f848faSopenharmony_ci kobj_class_compile((kobj_class_t) &root_driver); 2774f9f848faSopenharmony_ci root_bus = make_device(NULL, "root", 0); 2775f9f848faSopenharmony_ci root_bus->desc = "System root bus"; 2776f9f848faSopenharmony_ci kobj_init((kobj_t) root_bus, (kobj_class_t) &root_driver); 2777f9f848faSopenharmony_ci root_bus->driver = &root_driver; 2778f9f848faSopenharmony_ci root_bus->state = DS_ATTACHED; 2779f9f848faSopenharmony_ci root_devclass = devclass_find_internal("root", NULL, FALSE); 2780f9f848faSopenharmony_ci //devinit(); 2781f9f848faSopenharmony_ci return (0); 2782f9f848faSopenharmony_ci 2783f9f848faSopenharmony_ci case MOD_SHUTDOWN: 2784f9f848faSopenharmony_ci device_shutdown(root_bus); 2785f9f848faSopenharmony_ci return (0); 2786f9f848faSopenharmony_ci default: 2787f9f848faSopenharmony_ci return (EOPNOTSUPP); 2788f9f848faSopenharmony_ci } 2789f9f848faSopenharmony_ci PDEBUG(("-")); 2790f9f848faSopenharmony_ci 2791f9f848faSopenharmony_ci return (0); 2792f9f848faSopenharmony_ci} 2793f9f848faSopenharmony_ci 2794f9f848faSopenharmony_ci/** 2795f9f848faSopenharmony_ci * @brief Automatically configure devices 2796f9f848faSopenharmony_ci * 2797f9f848faSopenharmony_ci * This function begins the autoconfiguration process by calling 2798f9f848faSopenharmony_ci * device_probe_and_attach() for each child of the @c root0 device. 2799f9f848faSopenharmony_ci */ 2800f9f848faSopenharmony_civoid 2801f9f848faSopenharmony_ciroot_bus_configure(void) 2802f9f848faSopenharmony_ci{ 2803f9f848faSopenharmony_ci PDEBUG(("+")); 2804f9f848faSopenharmony_ci root_bus_module_handler(NULL, MOD_LOAD, NULL); 2805f9f848faSopenharmony_ci 2806f9f848faSopenharmony_ci /* Eventually this will be split up, but this is sufficient for now. */ 2807f9f848faSopenharmony_ci bus_set_pass(BUS_PASS_DEFAULT); 2808f9f848faSopenharmony_ci PDEBUG(("-")); 2809f9f848faSopenharmony_ci} 2810f9f848faSopenharmony_ci 2811f9f848faSopenharmony_ci/** 2812f9f848faSopenharmony_ci * @brief Module handler for registering device drivers 2813f9f848faSopenharmony_ci * 2814f9f848faSopenharmony_ci * This module handler is used to automatically register device 2815f9f848faSopenharmony_ci * drivers when modules are loaded. If @p what is MOD_LOAD, it calls 2816f9f848faSopenharmony_ci * devclass_add_driver() for the driver described by the 2817f9f848faSopenharmony_ci * driver_module_data structure pointed to by @p arg 2818f9f848faSopenharmony_ci */ 2819f9f848faSopenharmony_ciint 2820f9f848faSopenharmony_cidriver_module_handler(module_t mod, int what, void *arg) 2821f9f848faSopenharmony_ci{ 2822f9f848faSopenharmony_ci struct driver_module_data *dmd = NULL; 2823f9f848faSopenharmony_ci devclass_t bus_devclass; 2824f9f848faSopenharmony_ci kobj_class_t driver; 2825f9f848faSopenharmony_ci int error, pass; 2826f9f848faSopenharmony_ci 2827f9f848faSopenharmony_ci PDEBUG(("+")); 2828f9f848faSopenharmony_ci 2829f9f848faSopenharmony_ci dmd = (struct driver_module_data *)arg; 2830f9f848faSopenharmony_ci bus_devclass = devclass_find_internal(dmd->dmd_busname, NULL, TRUE); 2831f9f848faSopenharmony_ci if (bus_devclass == NULL) { 2832f9f848faSopenharmony_ci PDEBUG(("-")); 2833f9f848faSopenharmony_ci return EINVAL; 2834f9f848faSopenharmony_ci } 2835f9f848faSopenharmony_ci 2836f9f848faSopenharmony_ci error = 0; 2837f9f848faSopenharmony_ci 2838f9f848faSopenharmony_ci switch (what) { 2839f9f848faSopenharmony_ci case MOD_LOAD: 2840f9f848faSopenharmony_ci if (dmd->dmd_chainevh) 2841f9f848faSopenharmony_ci error = dmd->dmd_chainevh(mod,what,dmd->dmd_chainarg); 2842f9f848faSopenharmony_ci 2843f9f848faSopenharmony_ci pass = dmd->dmd_pass; 2844f9f848faSopenharmony_ci driver = dmd->dmd_driver; 2845f9f848faSopenharmony_ci PDEBUG(("Loading module: driver %s on bus %s (pass %d)", 2846f9f848faSopenharmony_ci DRIVERNAME(driver), dmd->dmd_busname, pass)); 2847f9f848faSopenharmony_ci error = devclass_add_driver(bus_devclass, driver, pass, 2848f9f848faSopenharmony_ci dmd->dmd_devclass); 2849f9f848faSopenharmony_ci break; 2850f9f848faSopenharmony_ci 2851f9f848faSopenharmony_ci case MOD_UNLOAD: 2852f9f848faSopenharmony_ci PDEBUG(("Unloading module: driver %s from bus %s", 2853f9f848faSopenharmony_ci DRIVERNAME(dmd->dmd_driver), 2854f9f848faSopenharmony_ci dmd->dmd_busname)); 2855f9f848faSopenharmony_ci error = devclass_delete_driver(bus_devclass, 2856f9f848faSopenharmony_ci dmd->dmd_driver); 2857f9f848faSopenharmony_ci 2858f9f848faSopenharmony_ci if (!error && dmd->dmd_chainevh) 2859f9f848faSopenharmony_ci error = dmd->dmd_chainevh(mod,what,dmd->dmd_chainarg); 2860f9f848faSopenharmony_ci break; 2861f9f848faSopenharmony_ci case MOD_QUIESCE: 2862f9f848faSopenharmony_ci PDEBUG(("Quiesce module: driver %s from bus %s", 2863f9f848faSopenharmony_ci DRIVERNAME(dmd->dmd_driver), 2864f9f848faSopenharmony_ci dmd->dmd_busname)); 2865f9f848faSopenharmony_ci error = devclass_quiesce_driver(bus_devclass, 2866f9f848faSopenharmony_ci dmd->dmd_driver); 2867f9f848faSopenharmony_ci 2868f9f848faSopenharmony_ci if (!error && dmd->dmd_chainevh) 2869f9f848faSopenharmony_ci error = dmd->dmd_chainevh(mod,what,dmd->dmd_chainarg); 2870f9f848faSopenharmony_ci break; 2871f9f848faSopenharmony_ci default: 2872f9f848faSopenharmony_ci error = EOPNOTSUPP; 2873f9f848faSopenharmony_ci break; 2874f9f848faSopenharmony_ci } 2875f9f848faSopenharmony_ci PDEBUG(("-")); 2876f9f848faSopenharmony_ci 2877f9f848faSopenharmony_ci return (error); 2878f9f848faSopenharmony_ci} 2879f9f848faSopenharmony_ci 2880f9f848faSopenharmony_ci#ifdef BUS_DEBUG 2881f9f848faSopenharmony_ci 2882f9f848faSopenharmony_ci/* the _short versions avoid iteration by not calling anything that prints 2883f9f848faSopenharmony_ci * more than oneliners. I love oneliners. 2884f9f848faSopenharmony_ci */ 2885f9f848faSopenharmony_ci 2886f9f848faSopenharmony_cistatic void 2887f9f848faSopenharmony_ciprint_device_short(device_t dev, int indent) 2888f9f848faSopenharmony_ci{ 2889f9f848faSopenharmony_ci if (!dev) 2890f9f848faSopenharmony_ci return; 2891f9f848faSopenharmony_ci 2892f9f848faSopenharmony_ci indentprintf(("device %d: <%s> %sparent,%schildren,%s%s%s%s%s,%sivars,%ssoftc,busy=%d\n", 2893f9f848faSopenharmony_ci dev->unit, dev->desc, 2894f9f848faSopenharmony_ci (dev->parent? "":"no "), 2895f9f848faSopenharmony_ci (TAILQ_EMPTY(&dev->children)? "no ":""), 2896f9f848faSopenharmony_ci (dev->flags&DF_ENABLED? "enabled,":"disabled,"), 2897f9f848faSopenharmony_ci (dev->flags&DF_FIXEDCLASS? "fixed,":""), 2898f9f848faSopenharmony_ci (dev->flags&DF_WILDCARD? "wildcard,":""), 2899f9f848faSopenharmony_ci (dev->flags&DF_DESCMALLOCED? "descmalloced,":""), 2900f9f848faSopenharmony_ci (dev->flags&DF_REBID? "rebiddable,":""), 2901f9f848faSopenharmony_ci (dev->ivars? "":"no "), 2902f9f848faSopenharmony_ci (dev->softc? "":"no "), 2903f9f848faSopenharmony_ci dev->busy)); 2904f9f848faSopenharmony_ci} 2905f9f848faSopenharmony_ci 2906f9f848faSopenharmony_cistatic void 2907f9f848faSopenharmony_ciprint_device(device_t dev, int indent) 2908f9f848faSopenharmony_ci{ 2909f9f848faSopenharmony_ci if (!dev) 2910f9f848faSopenharmony_ci return; 2911f9f848faSopenharmony_ci 2912f9f848faSopenharmony_ci print_device_short(dev, indent); 2913f9f848faSopenharmony_ci 2914f9f848faSopenharmony_ci indentprintf(("Parent:\n")); 2915f9f848faSopenharmony_ci print_device_short(dev->parent, indent+1); 2916f9f848faSopenharmony_ci indentprintf(("Driver:\n")); 2917f9f848faSopenharmony_ci print_driver_short(dev->driver, indent+1); 2918f9f848faSopenharmony_ci indentprintf(("Devclass:\n")); 2919f9f848faSopenharmony_ci print_devclass_short(dev->devclass, indent+1); 2920f9f848faSopenharmony_ci} 2921f9f848faSopenharmony_ci 2922f9f848faSopenharmony_civoid 2923f9f848faSopenharmony_ciprint_device_tree_short(device_t dev, int indent) 2924f9f848faSopenharmony_ci/* print the device and all its children (indented) */ 2925f9f848faSopenharmony_ci{ 2926f9f848faSopenharmony_ci device_t child; 2927f9f848faSopenharmony_ci 2928f9f848faSopenharmony_ci if (!dev) 2929f9f848faSopenharmony_ci return; 2930f9f848faSopenharmony_ci 2931f9f848faSopenharmony_ci print_device_short(dev, indent); 2932f9f848faSopenharmony_ci 2933f9f848faSopenharmony_ci TAILQ_FOREACH(child, &dev->children, link) { 2934f9f848faSopenharmony_ci print_device_tree_short(child, indent+1); 2935f9f848faSopenharmony_ci } 2936f9f848faSopenharmony_ci} 2937f9f848faSopenharmony_ci 2938f9f848faSopenharmony_civoid 2939f9f848faSopenharmony_ciprint_device_tree(device_t dev, int indent) 2940f9f848faSopenharmony_ci/* print the device and all its children (indented) */ 2941f9f848faSopenharmony_ci{ 2942f9f848faSopenharmony_ci device_t child; 2943f9f848faSopenharmony_ci 2944f9f848faSopenharmony_ci if (!dev) 2945f9f848faSopenharmony_ci return; 2946f9f848faSopenharmony_ci 2947f9f848faSopenharmony_ci print_device(dev, indent); 2948f9f848faSopenharmony_ci 2949f9f848faSopenharmony_ci TAILQ_FOREACH(child, &dev->children, link) { 2950f9f848faSopenharmony_ci print_device_tree(child, indent+1); 2951f9f848faSopenharmony_ci } 2952f9f848faSopenharmony_ci} 2953f9f848faSopenharmony_ci 2954f9f848faSopenharmony_cistatic void 2955f9f848faSopenharmony_ciprint_driver_short(driver_t *driver, int indent) 2956f9f848faSopenharmony_ci{ 2957f9f848faSopenharmony_ci if (!driver) 2958f9f848faSopenharmony_ci return; 2959f9f848faSopenharmony_ci 2960f9f848faSopenharmony_ci indentprintf(("driver %s: softc size = %zd\n", 2961f9f848faSopenharmony_ci driver->name, driver->size)); 2962f9f848faSopenharmony_ci} 2963f9f848faSopenharmony_ci 2964f9f848faSopenharmony_cistatic void 2965f9f848faSopenharmony_ciprint_driver(driver_t *driver, int indent) 2966f9f848faSopenharmony_ci{ 2967f9f848faSopenharmony_ci if (!driver) 2968f9f848faSopenharmony_ci return; 2969f9f848faSopenharmony_ci 2970f9f848faSopenharmony_ci print_driver_short(driver, indent); 2971f9f848faSopenharmony_ci} 2972f9f848faSopenharmony_ci 2973f9f848faSopenharmony_cistatic void 2974f9f848faSopenharmony_ciprint_driver_list(driver_list_t drivers, int indent) 2975f9f848faSopenharmony_ci{ 2976f9f848faSopenharmony_ci driverlink_t driver = NULL; 2977f9f848faSopenharmony_ci 2978f9f848faSopenharmony_ci TAILQ_FOREACH(driver, &drivers, link) { 2979f9f848faSopenharmony_ci print_driver(driver->driver, indent); 2980f9f848faSopenharmony_ci } 2981f9f848faSopenharmony_ci} 2982f9f848faSopenharmony_ci 2983f9f848faSopenharmony_cistatic void 2984f9f848faSopenharmony_ciprint_devclass_short(devclass_t dc, int indent) 2985f9f848faSopenharmony_ci{ 2986f9f848faSopenharmony_ci if ( !dc ) 2987f9f848faSopenharmony_ci return; 2988f9f848faSopenharmony_ci 2989f9f848faSopenharmony_ci indentprintf(("devclass %s: max units = %d\n", dc->name, dc->maxunit)); 2990f9f848faSopenharmony_ci} 2991f9f848faSopenharmony_ci 2992f9f848faSopenharmony_cistatic void 2993f9f848faSopenharmony_ciprint_devclass(devclass_t dc, int indent) 2994f9f848faSopenharmony_ci{ 2995f9f848faSopenharmony_ci int i; 2996f9f848faSopenharmony_ci 2997f9f848faSopenharmony_ci if ( !dc ) 2998f9f848faSopenharmony_ci return; 2999f9f848faSopenharmony_ci 3000f9f848faSopenharmony_ci print_devclass_short(dc, indent); 3001f9f848faSopenharmony_ci indentprintf(("Drivers:\n")); 3002f9f848faSopenharmony_ci print_driver_list(dc->drivers, indent+1); 3003f9f848faSopenharmony_ci 3004f9f848faSopenharmony_ci indentprintf(("Devices:\n")); 3005f9f848faSopenharmony_ci for (i = 0; i < dc->maxunit; i++) 3006f9f848faSopenharmony_ci if (dc->devices[i]) 3007f9f848faSopenharmony_ci print_device(dc->devices[i], indent+1); 3008f9f848faSopenharmony_ci} 3009f9f848faSopenharmony_ci 3010f9f848faSopenharmony_civoid 3011f9f848faSopenharmony_ciprint_devclass_list_short(void) 3012f9f848faSopenharmony_ci{ 3013f9f848faSopenharmony_ci devclass_t dc; 3014f9f848faSopenharmony_ci 3015f9f848faSopenharmony_ci printf("Short listing of devclasses, drivers & devices:\n"); 3016f9f848faSopenharmony_ci TAILQ_FOREACH(dc, &devclasses, link) { 3017f9f848faSopenharmony_ci print_devclass_short(dc, 0); 3018f9f848faSopenharmony_ci } 3019f9f848faSopenharmony_ci} 3020f9f848faSopenharmony_ci 3021f9f848faSopenharmony_civoid 3022f9f848faSopenharmony_ciprint_devclass_list(void) 3023f9f848faSopenharmony_ci{ 3024f9f848faSopenharmony_ci devclass_t dc; 3025f9f848faSopenharmony_ci 3026f9f848faSopenharmony_ci printf("Full listing of devclasses, drivers & devices:\n"); 3027f9f848faSopenharmony_ci TAILQ_FOREACH(dc, &devclasses, link) { 3028f9f848faSopenharmony_ci print_devclass(dc, 0); 3029f9f848faSopenharmony_ci } 3030f9f848faSopenharmony_ci} 3031f9f848faSopenharmony_ci 3032f9f848faSopenharmony_ci#endif 3033f9f848faSopenharmony_ci 3034f9f848faSopenharmony_ci/* port for interrupt setup and teardown */ 3035f9f848faSopenharmony_ciint 3036f9f848faSopenharmony_cibus_setup_intr(int irq, int flags, driver_intr_t *intr, void *arg) 3037f9f848faSopenharmony_ci{ 3038f9f848faSopenharmony_ci int ret; 3039f9f848faSopenharmony_ci HwiIrqParam irqParam = {0}; 3040f9f848faSopenharmony_ci 3041f9f848faSopenharmony_ci if (OS_INT_ACTIVE) { 3042f9f848faSopenharmony_ci return OS_ERRNO_HWI_INTERR; 3043f9f848faSopenharmony_ci } 3044f9f848faSopenharmony_ci 3045f9f848faSopenharmony_ci irqParam.swIrq = irq; 3046f9f848faSopenharmony_ci irqParam.pDevId = arg; 3047f9f848faSopenharmony_ci 3048f9f848faSopenharmony_ci ret = LOS_HwiCreate(irq, 0, (HWI_MODE_T)flags, (HWI_PROC_FUNC)intr, &irqParam); 3049f9f848faSopenharmony_ci if (ret == LOS_OK) { 3050f9f848faSopenharmony_ci HalIrqUnmask(irq); 3051f9f848faSopenharmony_ci } 3052f9f848faSopenharmony_ci return ret; 3053f9f848faSopenharmony_ci} 3054f9f848faSopenharmony_ciint 3055f9f848faSopenharmony_cibus_teardown_intr(int irq, void *arg) 3056f9f848faSopenharmony_ci{ 3057f9f848faSopenharmony_ci HwiIrqParam irqParam = {0}; 3058f9f848faSopenharmony_ci 3059f9f848faSopenharmony_ci if (OS_INT_ACTIVE) { 3060f9f848faSopenharmony_ci return -1; 3061f9f848faSopenharmony_ci } 3062f9f848faSopenharmony_ci 3063f9f848faSopenharmony_ci irqParam.swIrq = irq; 3064f9f848faSopenharmony_ci irqParam.pDevId = arg; 3065f9f848faSopenharmony_ci 3066f9f848faSopenharmony_ci return LOS_HwiDelete(irq, &irqParam); 3067f9f848faSopenharmony_ci} 3068