subr_bus.c revision 138402
1148330Snetchild/*- 2148330Snetchild * Copyright (c) 1997,1998,2003 Doug Rabson 3148330Snetchild * All rights reserved. 4148330Snetchild * 5148330Snetchild * Redistribution and use in source and binary forms, with or without 6148330Snetchild * modification, are permitted provided that the following conditions 7148330Snetchild * are met: 8148330Snetchild * 1. Redistributions of source code must retain the above copyright 9148330Snetchild * notice, this list of conditions and the following disclaimer. 10148330Snetchild * 2. Redistributions in binary form must reproduce the above copyright 11148330Snetchild * notice, this list of conditions and the following disclaimer in the 12148330Snetchild * documentation and/or other materials provided with the distribution. 13148330Snetchild * 14148543Snetchild * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15148543Snetchild * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16148330Snetchild * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17195754Smarcus * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18195754Smarcus * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19195699Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20195699Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21195699Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22195699Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23195656Strasz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24195656Strasz * SUCH DAMAGE. 25195656Strasz */ 26195656Strasz 27195656Strasz#include <sys/cdefs.h> 28195230Sdfr__FBSDID("$FreeBSD: head/sys/kern/subr_bus.c 138402 2004-12-05 20:58:56Z obrien $"); 29195230Sdfr 30194860Sthompsa#include "opt_bus.h" 31195096Santoine 32195096Santoine#define __RMAN_RESOURCE_VISIBLE 33195096Santoine#include <sys/param.h> 34195096Santoine#include <sys/conf.h> 35195096Santoine#include <sys/filio.h> 36195096Santoine#include <sys/lock.h> 37195096Santoine#include <sys/kernel.h> 38195096Santoine#include <sys/kobj.h> 39195096Santoine#include <sys/malloc.h> 40195096Santoine#include <sys/module.h> 41195096Santoine#include <sys/mutex.h> 42195096Santoine#include <sys/poll.h> 43195096Santoine#include <sys/proc.h> 44195096Santoine#include <sys/condvar.h> 45195096Santoine#include <sys/queue.h> 46195096Santoine#include <machine/bus.h> 47195096Santoine#include <sys/rman.h> 48195096Santoine#include <sys/selinfo.h> 49195096Santoine#include <sys/signalvar.h> 50195096Santoine#include <sys/sysctl.h> 51195096Santoine#include <sys/systm.h> 52195096Santoine#include <sys/uio.h> 53195096Santoine#include <sys/bus.h> 54195096Santoine 55195096Santoine#include <machine/stdarg.h> 56195096Santoine 57195096Santoine#include <vm/uma.h> 58195096Santoine 59195096SantoineSYSCTL_NODE(_hw, OID_AUTO, bus, CTLFLAG_RW, NULL, NULL); 60195096SantoineSYSCTL_NODE(, OID_AUTO, dev, CTLFLAG_RW, NULL, NULL); 61195096Santoine 62195096Santoine/* 63195096Santoine * Used to attach drivers to devclasses. 64195096Santoine */ 65195096Santoinetypedef struct driverlink *driverlink_t; 66195096Santoinestruct driverlink { 67195096Santoine kobj_class_t driver; 68195096Santoine TAILQ_ENTRY(driverlink) link; /* list of drivers in devclass */ 69195096Santoine}; 70195096Santoine 71195096Santoine/* 72195096Santoine * Forward declarations 73195096Santoine */ 74195096Santoinetypedef TAILQ_HEAD(devclass_list, devclass) devclass_list_t; 75195096Santoinetypedef TAILQ_HEAD(driver_list, driverlink) driver_list_t; 76195096Santoinetypedef TAILQ_HEAD(device_list, device) device_list_t; 77195096Santoine 78195096Santoinestruct devclass { 79195096Santoine TAILQ_ENTRY(devclass) link; 80195096Santoine devclass_t parent; /* parent in devclass hierarchy */ 81195096Santoine driver_list_t drivers; /* bus devclasses store drivers for bus */ 82195096Santoine char *name; 83195096Santoine device_t *devices; /* array of devices indexed by unit */ 84195096Santoine int maxunit; /* size of devices array */ 85195096Santoine 86195096Santoine struct sysctl_ctx_list sysctl_ctx; 87195096Santoine struct sysctl_oid *sysctl_tree; 88195096Santoine}; 89195096Santoine 90193513Sed/** 91193513Sed * @brief Implementation of device. 92193308Sed */ 93193308Sedstruct device { 94193308Sed /* 95195096Santoine * A device is a kernel object. The first field must be the 96195096Santoine * current ops table for the object. 97193113Sdougb */ 98193113Sdougb KOBJ_FIELDS; 99192926Sed 100192926Sed /* 101192926Sed * Device hierarchy. 102192901Sthompsa */ 103192901Sthompsa TAILQ_ENTRY(device) link; /**< list of devices in parent */ 104192901Sthompsa TAILQ_ENTRY(device) devlink; /**< global device list membership */ 105192901Sthompsa device_t parent; /**< parent of this device */ 106192901Sthompsa device_list_t children; /**< list of child devices */ 107192901Sthompsa 108192901Sthompsa /* 109192901Sthompsa * Details of this device. 110192901Sthompsa */ 111192901Sthompsa driver_t *driver; /**< current driver */ 112192901Sthompsa devclass_t devclass; /**< current device class */ 113192901Sthompsa int unit; /**< current unit number */ 114192901Sthompsa char* nameunit; /**< name+unit e.g. foodev0 */ 115192901Sthompsa char* desc; /**< driver specific description */ 116192901Sthompsa int busy; /**< count of calls to device_busy() */ 117192901Sthompsa device_state_t state; /**< current device state */ 118192901Sthompsa u_int32_t devflags; /**< api level flags for device_get_flags() */ 119192901Sthompsa u_short flags; /**< internal device flags */ 120192901Sthompsa#define DF_ENABLED 1 /* device should be probed/attached */ 121192901Sthompsa#define DF_FIXEDCLASS 2 /* devclass specified at create time */ 122192901Sthompsa#define DF_WILDCARD 4 /* unit was originally wildcard */ 123192901Sthompsa#define DF_DESCMALLOCED 8 /* description was malloced */ 124192901Sthompsa#define DF_QUIET 16 /* don't print verbose attach message */ 125192901Sthompsa#define DF_DONENOMATCH 32 /* don't execute DEVICE_NOMATCH again */ 126192901Sthompsa#define DF_EXTERNALSOFTC 64 /* softc not allocated by us */ 127192901Sthompsa#define DF_REBID 128 /* Can rebid after attach */ 128192901Sthompsa u_char order; /**< order from device_add_child_ordered() */ 129192901Sthompsa u_char pad; 130192901Sthompsa void *ivars; /**< instance variables */ 131192901Sthompsa void *softc; /**< current driver's variables */ 132192901Sthompsa 133192901Sthompsa struct sysctl_ctx_list sysctl_ctx; /**< state for sysctl variables */ 134192901Sthompsa struct sysctl_oid *sysctl_tree; /**< state for sysctl variables */ 135192916Sdougb}; 136195096Santoine 137192916Sdougbstatic MALLOC_DEFINE(M_BUS, "bus", "Bus data structures"); 138192580Srwatsonstatic MALLOC_DEFINE(M_BUS_SC, "bus-sc", "Bus data structures, softc"); 139192580Srwatson 140192580Srwatson#ifdef BUS_DEBUG 141192580Srwatson 142192650Santoinestatic int bus_debug = 1; 143192580SrwatsonTUNABLE_INT("bus.debug", &bus_debug); 144192650SantoineSYSCTL_INT(_debug, OID_AUTO, bus_debug, CTLFLAG_RW, &bus_debug, 0, 145192650Santoine "Debug bus code"); 146192650Santoine 147191250Santoine#define PDEBUG(a) if (bus_debug) {printf("%s:%d: ", __func__, __LINE__), printf a; printf("\n");} 148191250Santoine#define DEVICENAME(d) ((d)? device_get_name(d): "no device") 149191250Santoine#define DRIVERNAME(d) ((d)? d->name : "no driver") 150191250Santoine#define DEVCLANAME(d) ((d)? d->name : "no devclass") 151191250Santoine 152191250Santoine/** 153191250Santoine * Produce the indenting, indent*2 spaces plus a '.' ahead of that to 154191250Santoine * prevent syslog from deleting initial spaces 155191250Santoine */ 156191250Santoine#define indentprintf(p) do { int iJ; printf("."); for (iJ=0; iJ<indent; iJ++) printf(" "); printf p ; } while (0) 157191250Santoine 158191250Santoinestatic void print_device_short(device_t dev, int indent); 159191250Santoinestatic void print_device(device_t dev, int indent); 160191250Santoinevoid print_device_tree_short(device_t dev, int indent); 161191250Santoinevoid print_device_tree(device_t dev, int indent); 162191146Smaximstatic void print_driver_short(driver_t *driver, int indent); 163191146Smaximstatic void print_driver(driver_t *driver, int indent); 164191146Smaximstatic void print_driver_list(driver_list_t drivers, int indent); 165191146Smaximstatic void print_devclass_short(devclass_t dc, int indent); 166191146Smaximstatic void print_devclass(devclass_t dc, int indent); 167191146Smaximvoid print_devclass_list_short(void); 168190894Sdangervoid print_devclass_list(void); 169190905Sdanger 170191250Santoine#else 171191250Santoine/* Make the compiler ignore the function calls */ 172190751Sed#define PDEBUG(a) /* nop */ 173190864Sru#define DEVICENAME(d) /* nop */ 174190864Sru#define DRIVERNAME(d) /* nop */ 175190751Sed#define DEVCLANAME(d) /* nop */ 176190751Sed 177190751Sed#define print_device_short(d,i) /* nop */ 178190751Sed#define print_device(d,i) /* nop */ 179190751Sed#define print_device_tree_short(d,i) /* nop */ 180190751Sed#define print_device_tree(d,i) /* nop */ 181190864Sru#define print_driver_short(d,i) /* nop */ 182190751Sed#define print_driver(d,i) /* nop */ 183190751Sed#define print_driver_list(d,i) /* nop */ 184190751Sed#define print_devclass_short(d,i) /* nop */ 185190751Sed#define print_devclass(d,i) /* nop */ 186190751Sed#define print_devclass_list_short() /* nop */ 187190751Sed#define print_devclass_list() /* nop */ 188190751Sed#endif 189190751Sed 190190751Sed/* 191190751Sed * dev sysctl tree 192190864Sru */ 193190751Sed 194190864Sruenum { 195190772Sru DEVCLASS_SYSCTL_PARENT, 196190772Sru}; 197190772Sru 198190772Srustatic int 199190772Srudevclass_sysctl_handler(SYSCTL_HANDLER_ARGS) 200190100Sthompsa{ 201190100Sthompsa devclass_t dc = (devclass_t)arg1; 202189977Sbrueffer const char *value; 203189977Sbrueffer char *buf; 204189585Sthompsa int error; 205189585Sthompsa 206189607Sthompsa buf = NULL; 207189607Sthompsa switch (arg2) { 208189607Sthompsa case DEVCLASS_SYSCTL_PARENT: 209189585Sthompsa value = dc->parent ? dc->parent->name : ""; 210191250Santoine break; 211190772Sru default: 212190772Sru return (EINVAL); 213190772Sru } 214190772Sru error = SYSCTL_OUT(req, value, strlen(value)); 215190772Sru if (buf != NULL) 216190772Sru free(buf, M_BUS); 217189092Sed return (error); 218189092Sed} 219190772Sru 220190772Srustatic void 221190772Srudevclass_sysctl_init(devclass_t dc) 222188948Sthompsa{ 223189000Sthompsa 224189000Sthompsa if (dc->sysctl_tree != NULL) 225189000Sthompsa return; 226189000Sthompsa sysctl_ctx_init(&dc->sysctl_ctx); 227189000Sthompsa dc->sysctl_tree = SYSCTL_ADD_NODE(&dc->sysctl_ctx, 228189000Sthompsa SYSCTL_STATIC_CHILDREN(_dev), OID_AUTO, dc->name, 229189000Sthompsa CTLFLAG_RD, 0, ""); 230189000Sthompsa SYSCTL_ADD_PROC(&dc->sysctl_ctx, SYSCTL_CHILDREN(dc->sysctl_tree), 231189000Sthompsa OID_AUTO, "%parent", CTLFLAG_RD, 232189000Sthompsa dc, DEVCLASS_SYSCTL_PARENT, devclass_sysctl_handler, "A", 233189000Sthompsa "parent class"); 234189000Sthompsa} 235189000Sthompsa 236189000Sthompsaenum { 237188948Sthompsa DEVICE_SYSCTL_DESC, 238188948Sthompsa DEVICE_SYSCTL_DRIVER, 239188948Sthompsa DEVICE_SYSCTL_LOCATION, 240188948Sthompsa DEVICE_SYSCTL_PNPINFO, 241188948Sthompsa DEVICE_SYSCTL_PARENT, 242188948Sthompsa}; 243188948Sthompsa 244188948Sthompsastatic int 245188948Sthompsadevice_sysctl_handler(SYSCTL_HANDLER_ARGS) 246188948Sthompsa{ 247188948Sthompsa device_t dev = (device_t)arg1; 248188948Sthompsa const char *value; 249188948Sthompsa char *buf; 250188948Sthompsa int error; 251188948Sthompsa 252188948Sthompsa buf = NULL; 253188948Sthompsa switch (arg2) { 254191250Santoine case DEVICE_SYSCTL_DESC: 255191250Santoine value = dev->desc ? dev->desc : ""; 256188948Sthompsa break; 257188948Sthompsa case DEVICE_SYSCTL_DRIVER: 258188948Sthompsa value = dev->driver ? dev->driver->name : ""; 259188948Sthompsa break; 260188948Sthompsa case DEVICE_SYSCTL_LOCATION: 261188948Sthompsa value = buf = malloc(1024, M_BUS, M_WAITOK | M_ZERO); 262188948Sthompsa bus_child_location_str(dev, buf, 1024); 263188948Sthompsa break; 264188948Sthompsa case DEVICE_SYSCTL_PNPINFO: 265188948Sthompsa value = buf = malloc(1024, M_BUS, M_WAITOK | M_ZERO); 266188948Sthompsa bus_child_pnpinfo_str(dev, buf, 1024); 267188948Sthompsa break; 268188948Sthompsa case DEVICE_SYSCTL_PARENT: 269188948Sthompsa value = dev->parent ? dev->parent->nameunit : ""; 270188948Sthompsa break; 271188948Sthompsa default: 272188948Sthompsa return (EINVAL); 273188948Sthompsa } 274188948Sthompsa error = SYSCTL_OUT(req, value, strlen(value)); 275188948Sthompsa if (buf != NULL) 276188948Sthompsa free(buf, M_BUS); 277188948Sthompsa return (error); 278188948Sthompsa} 279188948Sthompsa 280188948Sthompsastatic void 281188652Seddevice_sysctl_init(device_t dev) 282188652Sed{ 283188652Sed devclass_t dc = dev->devclass; 284188652Sed 285188102Sgabor if (dev->sysctl_tree != NULL) 286188102Sgabor return; 287187694Santoine devclass_sysctl_init(dc); 288187694Santoine sysctl_ctx_init(&dev->sysctl_ctx); 289187694Santoine dev->sysctl_tree = SYSCTL_ADD_NODE(&dev->sysctl_ctx, 290187694Santoine SYSCTL_CHILDREN(dc->sysctl_tree), OID_AUTO, 291187694Santoine dev->nameunit + strlen(dc->name), 292186716Santoine CTLFLAG_RD, 0, ""); 293186716Santoine SYSCTL_ADD_PROC(&dev->sysctl_ctx, SYSCTL_CHILDREN(dev->sysctl_tree), 294186437Sbz OID_AUTO, "%desc", CTLFLAG_RD, 295186437Sbz dev, DEVICE_SYSCTL_DESC, device_sysctl_handler, "A", 296185472Santoine "device description"); 297185472Santoine SYSCTL_ADD_PROC(&dev->sysctl_ctx, SYSCTL_CHILDREN(dev->sysctl_tree), 298185472Santoine OID_AUTO, "%driver", CTLFLAG_RD, 299185472Santoine dev, DEVICE_SYSCTL_DRIVER, device_sysctl_handler, "A", 300185472Santoine "device driver name"); 301183442Sed SYSCTL_ADD_PROC(&dev->sysctl_ctx, SYSCTL_CHILDREN(dev->sysctl_tree), 302183442Sed OID_AUTO, "%location", CTLFLAG_RD, 303183442Sed dev, DEVICE_SYSCTL_LOCATION, device_sysctl_handler, "A", 304183442Sed "device location relative to parent"); 305183442Sed SYSCTL_ADD_PROC(&dev->sysctl_ctx, SYSCTL_CHILDREN(dev->sysctl_tree), 306183442Sed OID_AUTO, "%pnpinfo", CTLFLAG_RD, 307183113Sattilio dev, DEVICE_SYSCTL_PNPINFO, device_sysctl_handler, "A", 308183235Santoine "device identification"); 309183235Santoine SYSCTL_ADD_PROC(&dev->sysctl_ctx, SYSCTL_CHILDREN(dev->sysctl_tree), 310183026Santoine OID_AUTO, "%parent", CTLFLAG_RD, 311183026Santoine dev, DEVICE_SYSCTL_PARENT, device_sysctl_handler, "A", 312182105Sed "parent device"); 313182105Sed} 314182518Santoine 315182518Santoinestatic void 316182518Santoinedevice_sysctl_fini(device_t dev) 317182518Santoine{ 318182518Santoine if (dev->sysctl_tree == NULL) 319182518Santoine return; 320182518Santoine sysctl_ctx_free(&dev->sysctl_ctx); 321182518Santoine dev->sysctl_tree = NULL; 322182518Santoine} 323182518Santoine 324182518Santoine/* 325182518Santoine * /dev/devctl implementation 326182518Santoine */ 327182518Santoine 328182518Santoine/* 329182518Santoine * This design allows only one reader for /dev/devctl. This is not desirable 330182518Santoine * in the long run, but will get a lot of hair out of this implementation. 331182518Santoine * Maybe we should make this device a clonable device. 332181905Sed * 333181905Sed * Also note: we specifically do not attach a device to the device_t tree 334181905Sed * to avoid potential chicken and egg problems. One could argue that all 335180800Sed * of this belongs to the root node. One could also further argue that the 336180800Sed * sysctl interface that we have not might more properly be an ioctl 337180614Smarcel * interface, but at this stage of the game, I'm not inclined to rock that 338180614Smarcel * boat. 339180614Smarcel * 340180614Smarcel * I'm also not sure that the SIGIO support is done correctly or not, as 341180614Smarcel * I copied it from a driver that had SIGIO support that likely hasn't been 342180614Smarcel * tested since 3.4 or 2.2.8! 343180331Smarcel */ 344180331Smarcel 345180331Smarcelstatic int sysctl_devctl_disable(SYSCTL_HANDLER_ARGS); 346180331Smarcelstatic int devctl_disable = 0; 347180331SmarcelTUNABLE_INT("hw.bus.devctl_disable", &devctl_disable); 348180267SjhbSYSCTL_PROC(_hw_bus, OID_AUTO, devctl_disable, CTLTYPE_INT | CTLFLAG_RW, 0, 0, 349180267Sjhb sysctl_devctl_disable, "I", "devctl disable"); 350180267Sjhb 351180265Sjhbstatic d_open_t devopen; 352180265Sjhbstatic d_close_t devclose; 353180265Sjhbstatic d_read_t devread; 354180259Sjhbstatic d_ioctl_t devioctl; 355180259Sjhbstatic d_poll_t devpoll; 356180259Sjhb 357180259Sjhb#define CDEV_MAJOR 173 358180259Sjhbstatic struct cdevsw dev_cdevsw = { 359180257Sjhb .d_version = D_VERSION, 360180257Sjhb .d_flags = D_NEEDGIANT, 361180257Sjhb .d_open = devopen, 362180259Sjhb .d_close = devclose, 363180257Sjhb .d_read = devread, 364180257Sjhb .d_ioctl = devioctl, 365180248Smarcel .d_poll = devpoll, 366180248Smarcel .d_name = "devctl", 367180248Smarcel .d_maj = CDEV_MAJOR, 368180248Smarcel}; 369180248Smarcel 370180230Smarcelstruct dev_event_info 371180230Smarcel{ 372180230Smarcel char *dei_data; 373180230Smarcel TAILQ_ENTRY(dev_event_info) dei_link; 374180230Smarcel}; 375180230Smarcel 376180230SmarcelTAILQ_HEAD(devq, dev_event_info); 377180230Smarcel 378180159Sdangerstatic struct dev_softc 379180159Sdanger{ 380180159Sdanger int inuse; 381180496Santoine int nonblock; 382180496Santoine struct mtx mtx; 383180496Santoine struct cv cv; 384180496Santoine struct selinfo sel; 385179784Sed struct devq devq; 386179784Sed struct proc *async_proc; 387179784Sed} devsoftc; 388179784Sed 389179784Sedstatic struct cdev *devctl_dev; 390179692Smarcel 391179692Smarcelstatic void 392179692Smarceldevinit(void) 393179315Sbz{ 394179315Sbz devctl_dev = make_dev(&dev_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, 395179315Sbz "devctl"); 396179315Sbz mtx_init(&devsoftc.mtx, "dev mtx", "devd", MTX_DEF); 397179315Sbz cv_init(&devsoftc.cv, "dev cv"); 398179315Sbz TAILQ_INIT(&devsoftc.devq); 399179315Sbz} 400179315Sbz 401179315Sbzstatic int 402179315Sbzdevopen(struct cdev *dev, int oflags, int devtype, d_thread_t *td) 403179315Sbz{ 404179315Sbz if (devsoftc.inuse) 405179315Sbz return (EBUSY); 406179315Sbz /* move to init */ 407179315Sbz devsoftc.inuse = 1; 408179315Sbz devsoftc.nonblock = 0; 409179315Sbz devsoftc.async_proc = NULL; 410179315Sbz return (0); 411179315Sbz} 412179315Sbz 413179315Sbzstatic int 414179315Sbzdevclose(struct cdev *dev, int fflag, int devtype, d_thread_t *td) 415179315Sbz{ 416179315Sbz devsoftc.inuse = 0; 417179315Sbz mtx_lock(&devsoftc.mtx); 418179315Sbz cv_broadcast(&devsoftc.cv); 419179315Sbz mtx_unlock(&devsoftc.mtx); 420179315Sbz 421179315Sbz return (0); 422179315Sbz} 423179315Sbz 424179315Sbz/* 425179315Sbz * The read channel for this device is used to report changes to 426179315Sbz * userland in realtime. We are required to free the data as well as 427179315Sbz * the n1 object because we allocate them separately. Also note that 428179315Sbz * we return one record at a time. If you try to read this device a 429179315Sbz * character at a time, you will loose the rest of the data. Listening 430179315Sbz * programs are expected to cope. 431179315Sbz */ 432179315Sbzstatic int 433179315Sbzdevread(struct cdev *dev, struct uio *uio, int ioflag) 434179315Sbz{ 435179315Sbz struct dev_event_info *n1; 436179315Sbz int rv; 437179315Sbz 438179315Sbz mtx_lock(&devsoftc.mtx); 439179315Sbz while (TAILQ_EMPTY(&devsoftc.devq)) { 440179315Sbz if (devsoftc.nonblock) { 441179315Sbz mtx_unlock(&devsoftc.mtx); 442179315Sbz return (EAGAIN); 443179315Sbz } 444179315Sbz rv = cv_wait_sig(&devsoftc.cv, &devsoftc.mtx); 445179315Sbz if (rv) { 446179315Sbz /* 447179315Sbz * Need to translate ERESTART to EINTR here? -- jake 448179315Sbz */ 449179315Sbz mtx_unlock(&devsoftc.mtx); 450179315Sbz return (rv); 451179315Sbz } 452179315Sbz } 453179315Sbz n1 = TAILQ_FIRST(&devsoftc.devq); 454179315Sbz TAILQ_REMOVE(&devsoftc.devq, n1, dei_link); 455179315Sbz mtx_unlock(&devsoftc.mtx); 456179315Sbz rv = uiomove(n1->dei_data, strlen(n1->dei_data), uio); 457179315Sbz free(n1->dei_data, M_BUS); 458179315Sbz free(n1, M_BUS); 459179315Sbz return (rv); 460179315Sbz} 461179315Sbz 462179315Sbzstatic int 463179315Sbzdevioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, d_thread_t *td) 464179315Sbz{ 465179315Sbz switch (cmd) { 466179315Sbz 467179315Sbz case FIONBIO: 468179315Sbz if (*(int*)data) 469179315Sbz devsoftc.nonblock = 1; 470179315Sbz else 471179315Sbz devsoftc.nonblock = 0; 472179315Sbz return (0); 473179315Sbz case FIOASYNC: 474179315Sbz if (*(int*)data) 475179315Sbz devsoftc.async_proc = td->td_proc; 476179315Sbz else 477179315Sbz devsoftc.async_proc = NULL; 478179315Sbz return (0); 479179315Sbz 480179315Sbz /* (un)Support for other fcntl() calls. */ 481179315Sbz case FIOCLEX: 482179315Sbz case FIONCLEX: 483179315Sbz case FIONREAD: 484179315Sbz case FIOSETOWN: 485179315Sbz case FIOGETOWN: 486179315Sbz default: 487179315Sbz break; 488179315Sbz } 489179315Sbz return (ENOTTY); 490179315Sbz} 491179315Sbz 492179315Sbzstatic int 493179315Sbzdevpoll(struct cdev *dev, int events, d_thread_t *td) 494179315Sbz{ 495179315Sbz int revents = 0; 496179315Sbz 497179315Sbz mtx_lock(&devsoftc.mtx); 498179315Sbz if (events & (POLLIN | POLLRDNORM)) { 499179315Sbz if (!TAILQ_EMPTY(&devsoftc.devq)) 500179315Sbz revents = events & (POLLIN | POLLRDNORM); 501179315Sbz else 502179315Sbz selrecord(td, &devsoftc.sel); 503179315Sbz } 504179315Sbz mtx_unlock(&devsoftc.mtx); 505179315Sbz 506179315Sbz return (revents); 507179361Santoine} 508179361Santoine 509179361Santoine/** 510179361Santoine * @brief Queue data to be read from the devctl device 511179361Santoine * 512179361Santoine * Generic interface to queue data to the devctl device. It is 513179361Santoine * assumed that @p data is properly formatted. It is further assumed 514179361Santoine * that @p data is allocated using the M_BUS malloc type. 515179361Santoine */ 516179361Santoinevoid 517179361Santoinedevctl_queue_data(char *data) 518179361Santoine{ 519179361Santoine struct dev_event_info *n1 = NULL; 520179361Santoine struct proc *p; 521179361Santoine 522179361Santoine n1 = malloc(sizeof(*n1), M_BUS, M_NOWAIT); 523179361Santoine if (n1 == NULL) 524179361Santoine return; 525179361Santoine n1->dei_data = data; 526179361Santoine mtx_lock(&devsoftc.mtx); 527178924Santoine TAILQ_INSERT_TAIL(&devsoftc.devq, n1, dei_link); 528178924Santoine cv_broadcast(&devsoftc.cv); 529178924Santoine mtx_unlock(&devsoftc.mtx); 530178924Santoine selwakeup(&devsoftc.sel); 531178924Santoine p = devsoftc.async_proc; 532177831Sflz if (p != NULL) { 533177831Sflz PROC_LOCK(p); 534177831Sflz psignal(p, SIGIO); 535177831Sflz PROC_UNLOCK(p); 536177831Sflz } 537178331Santoine} 538178331Santoine 539178331Santoine/** 540178331Santoine * @brief Send a 'notification' to userland, using standard ways 541178331Santoine */ 542178331Santoinevoid 543178331Santoinedevctl_notify(const char *system, const char *subsystem, const char *type, 544178331Santoine const char *data) 545178331Santoine{ 546178331Santoine int len = 0; 547178331Santoine char *msg; 548178331Santoine 549178331Santoine if (system == NULL) 550178331Santoine return; /* BOGUS! Must specify system. */ 551178331Santoine if (subsystem == NULL) 552178331Santoine return; /* BOGUS! Must specify subsystem. */ 553178924Santoine if (type == NULL) 554178924Santoine return; /* BOGUS! Must specify type. */ 555178924Santoine len += strlen(" system=") + strlen(system); 556178924Santoine len += strlen(" subsystem=") + strlen(subsystem); 557176422Sthompsa len += strlen(" type=") + strlen(type); 558176422Sthompsa /* add in the data message plus newline. */ 559175690Sbrueffer if (data != NULL) 560175690Sbrueffer len += strlen(data); 561175690Sbrueffer len += 3; /* '!', '\n', and NUL */ 562175576Sattilio msg = malloc(len, M_BUS, M_NOWAIT); 563175576Sattilio if (msg == NULL) 564175227Sjhb return; /* Drop it on the floor */ 565175227Sjhb snprintf(msg, len, "!system=%s subsystem=%s type=%s %s\n", system, 566175227Sjhb subsystem, type, data); 567174426Sdougb devctl_queue_data(msg); 568174426Sdougb} 569174426Sdougb 570177153Sbrueffer/* 571177153Sbrueffer * Common routine that tries to make sending messages as easy as possible. 572174092Sbrooks * We allocate memory for the data, copy strings into that, but do not 573174092Sbrooks * free it unless there's an error. The dequeue part of the driver should 574174092Sbrooks * free the data. We don't send data when the device is disabled. We do 575174092Sbrooks * send data, even when we have no listeners, because we wish to avoid 576176956Santoine * races relating to startup and restart of listening applications. 577176956Santoine * 578176956Santoine * devaddq is designed to string together the type of event, with the 579176956Santoine * object of that event, plus the plug and play info and location info 580174092Sbrooks * for that event. This is likely most useful for devices, but less 581174061Sjb * useful for other consumers of this interface. Those should use 582174061Sjb * the devctl_queue_data() interface instead. 583175227Sjhb */ 584175227Sjhbstatic void 585173466Simpdevaddq(const char *type, const char *what, device_t dev) 586173466Simp{ 587173662Smarcel char *data = NULL; 588173662Smarcel char *loc = NULL; 589173662Smarcel char *pnp = NULL; 590173662Smarcel const char *parstr; 591173662Smarcel 592173662Smarcel if (devctl_disable) 593175227Sjhb return; 594175227Sjhb data = malloc(1024, M_BUS, M_NOWAIT); 595172983Smtm if (data == NULL) 596172983Smtm goto bad; 597172390Sbushman 598173176Sbushman /* get the bus specific location of this device */ 599172390Sbushman loc = malloc(1024, M_BUS, M_NOWAIT); 600172390Sbushman if (loc == NULL) 601172570Sru goto bad; 602172570Sru *loc = '\0'; 603171786Smarcel bus_child_location_str(dev, loc, 1024); 604171786Smarcel 605171786Smarcel /* Get the bus specific pnp info of this device */ 606171786Smarcel pnp = malloc(1024, M_BUS, M_NOWAIT); 607171696Sbz if (pnp == NULL) 608171696Sbz goto bad; 609179368Sbz *pnp = '\0'; 610171461Srwatson bus_child_pnpinfo_str(dev, pnp, 1024); 611171461Srwatson 612171461Srwatson /* Get the parent of this device, or / if high enough in the tree. */ 613171461Srwatson if (device_get_parent(dev) == NULL) 614171461Srwatson parstr = "."; /* Or '/' ? */ 615171461Srwatson else 616171461Srwatson parstr = device_get_nameunit(device_get_parent(dev)); 617171461Srwatson /* String it all together. */ 618171461Srwatson snprintf(data, 1024, "%s%s at %s %s on %s\n", type, what, loc, pnp, 619171461Srwatson parstr); 620171461Srwatson free(loc, M_BUS); 621171461Srwatson free(pnp, M_BUS); 622171461Srwatson devctl_queue_data(data); 623171461Srwatson return; 624171461Srwatsonbad: 625171461Srwatson free(pnp, M_BUS); 626171461Srwatson free(loc, M_BUS); 627171461Srwatson free(data, M_BUS); 628171461Srwatson return; 629171461Srwatson} 630171461Srwatson 631171461Srwatson/* 632171461Srwatson * A device was added to the tree. We are called just after it successfully 633171461Srwatson * attaches (that is, probe and attach success for this device). No call 634171461Srwatson * is made if a device is merely parented into the tree. See devnomatch 635171461Srwatson * if probe fails. If attach fails, no notification is sent (but maybe 636171461Srwatson * we should have a different message for this). 637171461Srwatson */ 638171461Srwatsonstatic void 639171461Srwatsondevadded(device_t dev) 640171461Srwatson{ 641171461Srwatson char *pnp = NULL; 642171461Srwatson char *tmp = NULL; 643171461Srwatson 644171461Srwatson pnp = malloc(1024, M_BUS, M_NOWAIT); 645171461Srwatson if (pnp == NULL) 646171461Srwatson goto fail; 647171461Srwatson tmp = malloc(1024, M_BUS, M_NOWAIT); 648171461Srwatson if (tmp == NULL) 649171461Srwatson goto fail; 650171461Srwatson *pnp = '\0'; 651171461Srwatson bus_child_pnpinfo_str(dev, pnp, 1024); 652171461Srwatson snprintf(tmp, 1024, "%s %s", device_get_nameunit(dev), pnp); 653171461Srwatson devaddq("+", tmp, dev); 654171461Srwatsonfail: 655171461Srwatson if (pnp != NULL) 656171461Srwatson free(pnp, M_BUS); 657171461Srwatson if (tmp != NULL) 658171461Srwatson free(tmp, M_BUS); 659171461Srwatson return; 660171461Srwatson} 661171461Srwatson 662171461Srwatson/* 663171461Srwatson * A device was removed from the tree. We are called just before this 664171461Srwatson * happens. 665171461Srwatson */ 666171461Srwatsonstatic void 667171461Srwatsondevremoved(device_t dev) 668171461Srwatson{ 669171461Srwatson char *pnp = NULL; 670171461Srwatson char *tmp = NULL; 671171461Srwatson 672171461Srwatson pnp = malloc(1024, M_BUS, M_NOWAIT); 673171461Srwatson if (pnp == NULL) 674171461Srwatson goto fail; 675171461Srwatson tmp = malloc(1024, M_BUS, M_NOWAIT); 676171461Srwatson if (tmp == NULL) 677171461Srwatson goto fail; 678171461Srwatson *pnp = '\0'; 679171461Srwatson bus_child_pnpinfo_str(dev, pnp, 1024); 680171461Srwatson snprintf(tmp, 1024, "%s %s", device_get_nameunit(dev), pnp); 681171461Srwatson devaddq("-", tmp, dev); 682176956Santoinefail: 683176956Santoine if (pnp != NULL) 684176956Santoine free(pnp, M_BUS); 685176956Santoine if (tmp != NULL) 686176956Santoine free(tmp, M_BUS); 687176956Santoine return; 688171274Sbz} 689171274Sbz 690171274Sbz/* 691171274Sbz * Called when there's no match for this device. This is only called 692171274Sbz * the first time that no match happens, so we don't keep getitng this 693171274Sbz * message. Should that prove to be undesirable, we can change it. 694171274Sbz * This is called when all drivers that can attach to a given bus 695171274Sbz * decline to accept this device. Other errrors may not be detected. 696171274Sbz */ 697179368Sbzstatic void 698171205Sbzdevnomatch(device_t dev) 699171205Sbz{ 700171205Sbz devaddq("?", "", dev); 701171205Sbz} 702171205Sbz 703171175Smlaierstatic int 704171175Smlaiersysctl_devctl_disable(SYSCTL_HANDLER_ARGS) 705171137Sbz{ 706171137Sbz struct dev_event_info *n1; 707171137Sbz int dis, error; 708171137Sbz 709171137Sbz dis = devctl_disable; 710171137Sbz error = sysctl_handle_int(oidp, &dis, 0, req); 711171137Sbz if (error || !req->newptr) 712171137Sbz return (error); 713171137Sbz mtx_lock(&devsoftc.mtx); 714171137Sbz devctl_disable = dis; 715171137Sbz if (dis) { 716171137Sbz while (!TAILQ_EMPTY(&devsoftc.devq)) { 717171137Sbz n1 = TAILQ_FIRST(&devsoftc.devq); 718171137Sbz TAILQ_REMOVE(&devsoftc.devq, n1, dei_link); 719171137Sbz free(n1->dei_data, M_BUS); 720171137Sbz free(n1, M_BUS); 721171137Sbz } 722171137Sbz } 723171137Sbz mtx_unlock(&devsoftc.mtx); 724171131Sthompsa return (0); 725171131Sthompsa} 726171143Sthompsa 727171023Srafan/* End of /dev/devctl code */ 728171023Srafan 729171023SrafanTAILQ_HEAD(,device) bus_data_devices; 730171023Srafanstatic int bus_data_generation = 1; 731171023Srafan 732171023Srafankobj_method_t null_methods[] = { 733171388Sdougb { 0, 0 } 734171388Sdougb}; 735171388Sdougb 736171388SdougbDEFINE_CLASS(null, null_methods, 0); 737170926Srafan 738170926Srafan/* 739170926Srafan * Devclass implementation 740170926Srafan */ 741170926Srafan 742170926Srafanstatic devclass_list_t devclasses = TAILQ_HEAD_INITIALIZER(devclasses); 743170926Srafan 744170926Srafan 745170926Srafan/** 746170926Srafan * @internal 747170926Srafan * @brief Find or create a device class 748170926Srafan * 749170926Srafan * If a device class with the name @p classname exists, return it, 750170926Srafan * otherwise if @p create is non-zero create and return a new device 751170926Srafan * class. 752170926Srafan * 753170926Srafan * If @p parentname is non-NULL, the parent of the devclass is set to 754170926Srafan * the devclass of that name. 755170926Srafan * 756170926Srafan * @param classname the devclass name to find or create 757170926Srafan * @param parentname the parent devclass name or @c NULL 758170926Srafan * @param create non-zero to create a devclass 759170926Srafan */ 760170926Srafanstatic devclass_t 761170926Srafandevclass_find_internal(const char *classname, const char *parentname, 762170926Srafan int create) 763170926Srafan{ 764170926Srafan devclass_t dc; 765170926Srafan 766170926Srafan PDEBUG(("looking for %s", classname)); 767170926Srafan if (!classname) 768170926Srafan return (NULL); 769170926Srafan 770170926Srafan TAILQ_FOREACH(dc, &devclasses, link) { 771170926Srafan if (!strcmp(dc->name, classname)) 772170926Srafan break; 773170926Srafan } 774170926Srafan 775170926Srafan if (create && !dc) { 776170926Srafan PDEBUG(("creating %s", classname)); 777170926Srafan dc = malloc(sizeof(struct devclass) + strlen(classname) + 1, 778176956Santoine M_BUS, M_NOWAIT|M_ZERO); 779176956Santoine if (!dc) 780176956Santoine return (NULL); 781176956Santoine dc->parent = NULL; 782176956Santoine dc->name = (char*) (dc + 1); 783176956Santoine strcpy(dc->name, classname); 784176956Santoine TAILQ_INIT(&dc->drivers); 785176956Santoine TAILQ_INSERT_TAIL(&devclasses, dc, link); 786176956Santoine 787176956Santoine bus_data_generation_update(); 788176956Santoine } 789176956Santoine if (parentname && dc && !dc->parent) { 790176956Santoine dc->parent = devclass_find_internal(parentname, 0, FALSE); 791176956Santoine } 792176956Santoine 793176956Santoine return (dc); 794176956Santoine} 795176956Santoine 796176956Santoine/** 797176956Santoine * @brief Create a device class 798176956Santoine * 799176956Santoine * If a device class with the name @p classname exists, return it, 800176956Santoine * otherwise create and return a new device class. 801176956Santoine * 802176956Santoine * @param classname the devclass name to find or create 803176956Santoine */ 804176956Santoinedevclass_t 805176956Santoinedevclass_create(const char *classname) 806176956Santoine{ 807176956Santoine return (devclass_find_internal(classname, 0, TRUE)); 808176956Santoine} 809176956Santoine 810176956Santoine/** 811176956Santoine * @brief Find a device class 812176956Santoine * 813176956Santoine * If a device class with the name @p classname exists, return it, 814171476Sdelphij * otherwise return @c NULL. 815171476Sdelphij * 816170312Sdelphij * @param classname the devclass name to find 817170312Sdelphij */ 818170926Srafandevclass_t 819173816Srudevclass_find(const char *classname) 820169815Sdelphij{ 821169815Sdelphij return (devclass_find_internal(classname, 0, FALSE)); 822169815Sdelphij} 823169815Sdelphij 824169815Sdelphij/** 825169815Sdelphij * @brief Add a device driver to a device class 826169815Sdelphij * 827169815Sdelphij * Add a device driver to a devclass. This is normally called 828169815Sdelphij * automatically by DRIVER_MODULE(). The BUS_DRIVER_ADDED() method of 829169815Sdelphij * all devices in the devclass will be called to allow them to attempt 830169815Sdelphij * to re-probe any unmatched children. 831169815Sdelphij * 832170204Sru * @param dc the devclass to edit 833169815Sdelphij * @param driver the driver to register 834169815Sdelphij */ 835169815Sdelphijint 836169815Sdelphijdevclass_add_driver(devclass_t dc, driver_t *driver) 837170204Sru{ 838169815Sdelphij driverlink_t dl; 839169815Sdelphij int i; 840169815Sdelphij 841169815Sdelphij PDEBUG(("%s", DRIVERNAME(driver))); 842169815Sdelphij 843169815Sdelphij dl = malloc(sizeof *dl, M_BUS, M_NOWAIT|M_ZERO); 844169815Sdelphij if (!dl) 845169815Sdelphij return (ENOMEM); 846169815Sdelphij 847169815Sdelphij /* 848169815Sdelphij * Compile the driver's methods. Also increase the reference count 849169815Sdelphij * so that the class doesn't get freed when the last instance 850169815Sdelphij * goes. This means we can safely use static methods and avoids a 851169815Sdelphij * double-free in devclass_delete_driver. 852169815Sdelphij */ 853169815Sdelphij kobj_class_compile((kobj_class_t) driver); 854169815Sdelphij 855169815Sdelphij /* 856169815Sdelphij * Make sure the devclass which the driver is implementing exists. 857169815Sdelphij */ 858169815Sdelphij devclass_find_internal(driver->name, 0, TRUE); 859169815Sdelphij 860169815Sdelphij dl->driver = driver; 861169815Sdelphij TAILQ_INSERT_TAIL(&dc->drivers, dl, link); 862169815Sdelphij driver->refs++; 863169815Sdelphij 864169815Sdelphij /* 865169815Sdelphij * Call BUS_DRIVER_ADDED for any existing busses in this class. 866169815Sdelphij */ 867169815Sdelphij for (i = 0; i < dc->maxunit; i++) 868169815Sdelphij if (dc->devices[i]) 869169815Sdelphij BUS_DRIVER_ADDED(dc->devices[i], driver); 870169815Sdelphij 871169815Sdelphij bus_data_generation_update(); 872169815Sdelphij return (0); 873169815Sdelphij} 874170204Sru 875169815Sdelphij/** 876169815Sdelphij * @brief Delete a device driver from a device class 877169815Sdelphij * 878170917Srafan * Delete a device driver from a devclass. This is normally called 879169815Sdelphij * automatically by DRIVER_MODULE(). 880169815Sdelphij * 881169815Sdelphij * If the driver is currently attached to any devices, 882169815Sdelphij * devclass_delete_driver() will first attempt to detach from each 883169815Sdelphij * device. If one of the detach calls fails, the driver will not be 884169815Sdelphij * deleted. 885169815Sdelphij * 886169815Sdelphij * @param dc the devclass to edit 887169815Sdelphij * @param driver the driver to unregister 888169815Sdelphij */ 889169815Sdelphijint 890169815Sdelphijdevclass_delete_driver(devclass_t busclass, driver_t *driver) 891169815Sdelphij{ 892169815Sdelphij devclass_t dc = devclass_find(driver->name); 893169815Sdelphij driverlink_t dl; 894169815Sdelphij device_t dev; 895169815Sdelphij int i; 896169815Sdelphij int error; 897169815Sdelphij 898169815Sdelphij PDEBUG(("%s from devclass %s", driver->name, DEVCLANAME(busclass))); 899169815Sdelphij 900169815Sdelphij if (!dc) 901169815Sdelphij return (0); 902169815Sdelphij 903169815Sdelphij /* 904169815Sdelphij * Find the link structure in the bus' list of drivers. 905169815Sdelphij */ 906169815Sdelphij TAILQ_FOREACH(dl, &busclass->drivers, link) { 907169815Sdelphij if (dl->driver == driver) 908169815Sdelphij break; 909169815Sdelphij } 910169815Sdelphij 911169815Sdelphij if (!dl) { 912169815Sdelphij PDEBUG(("%s not found in %s list", driver->name, 913169815Sdelphij busclass->name)); 914169815Sdelphij return (ENOENT); 915169815Sdelphij } 916169815Sdelphij 917169815Sdelphij /* 918169815Sdelphij * Disassociate from any devices. We iterate through all the 919169815Sdelphij * devices in the devclass of the driver and detach any which are 920169815Sdelphij * using the driver and which have a parent in the devclass which 921169815Sdelphij * we are deleting from. 922169815Sdelphij * 923169815Sdelphij * Note that since a driver can be in multiple devclasses, we 924169815Sdelphij * should not detach devices which are not children of devices in 925169815Sdelphij * the affected devclass. 926169815Sdelphij */ 927169815Sdelphij for (i = 0; i < dc->maxunit; i++) { 928170204Sru if (dc->devices[i]) { 929169815Sdelphij dev = dc->devices[i]; 930169815Sdelphij if (dev->driver == driver && dev->parent && 931169815Sdelphij dev->parent->devclass == busclass) { 932169815Sdelphij if ((error = device_detach(dev)) != 0) 933169815Sdelphij return (error); 934170190Sru device_set_driver(dev, NULL); 935169815Sdelphij } 936169815Sdelphij } 937169815Sdelphij } 938169815Sdelphij 939169815Sdelphij TAILQ_REMOVE(&busclass->drivers, dl, link); 940169815Sdelphij free(dl, M_BUS); 941169815Sdelphij 942169815Sdelphij driver->refs--; 943169815Sdelphij if (driver->refs == 0) 944169815Sdelphij kobj_class_free((kobj_class_t) driver); 945169815Sdelphij 946169815Sdelphij bus_data_generation_update(); 947170190Sru return (0); 948170190Sru} 949170190Sru 950170190Sru/** 951170190Sru * @internal 952170190Sru */ 953170190Srustatic driverlink_t 954171476Sdelphijdevclass_find_driver_internal(devclass_t dc, const char *classname) 955171476Sdelphij{ 956171476Sdelphij driverlink_t dl; 957171476Sdelphij 958171476Sdelphij PDEBUG(("%s in devclass %s", classname, DEVCLANAME(dc))); 959171476Sdelphij 960171476Sdelphij TAILQ_FOREACH(dl, &dc->drivers, link) { 961171476Sdelphij if (!strcmp(dl->driver->name, classname)) 962171476Sdelphij return (dl); 963171476Sdelphij } 964171476Sdelphij 965171476Sdelphij PDEBUG(("not found")); 966171476Sdelphij return (NULL); 967171476Sdelphij} 968171476Sdelphij 969171476Sdelphij/** 970171476Sdelphij * @brief Search a devclass for a driver 971171476Sdelphij * 972171476Sdelphij * This function searches the devclass's list of drivers and returns 973171476Sdelphij * the first driver whose name is @p classname or @c NULL if there is 974171476Sdelphij * no driver of that name. 975171476Sdelphij * 976171476Sdelphij * @param dc the devclass to search 977171476Sdelphij * @param classname the driver name to search for 978171476Sdelphij */ 979171476Sdelphijkobj_class_t 980171476Sdelphijdevclass_find_driver(devclass_t dc, const char *classname) 981171476Sdelphij{ 982171476Sdelphij driverlink_t dl; 983171476Sdelphij 984171476Sdelphij dl = devclass_find_driver_internal(dc, classname); 985171476Sdelphij if (dl) 986171476Sdelphij return (dl->driver); 987171476Sdelphij return (NULL); 988171476Sdelphij} 989171476Sdelphij 990171476Sdelphij/** 991171476Sdelphij * @brief Return the name of the devclass 992171476Sdelphij */ 993171476Sdelphijconst char * 994171476Sdelphijdevclass_get_name(devclass_t dc) 995171476Sdelphij{ 996171476Sdelphij return (dc->name); 997171476Sdelphij} 998171476Sdelphij 999171476Sdelphij/** 1000171476Sdelphij * @brief Find a device given a unit number 1001171476Sdelphij * 1002171476Sdelphij * @param dc the devclass to search 1003171476Sdelphij * @param unit the unit number to search for 1004171476Sdelphij * 1005171476Sdelphij * @returns the device with the given unit number or @c 1006171476Sdelphij * NULL if there is no such device 1007171476Sdelphij */ 1008171476Sdelphijdevice_t 1009171476Sdelphijdevclass_get_device(devclass_t dc, int unit) 1010171476Sdelphij{ 1011171476Sdelphij if (dc == NULL || unit < 0 || unit >= dc->maxunit) 1012171476Sdelphij return (NULL); 1013171476Sdelphij return (dc->devices[unit]); 1014171476Sdelphij} 1015171476Sdelphij 1016171476Sdelphij/** 1017171476Sdelphij * @brief Find the softc field of a device given a unit number 1018171476Sdelphij * 1019171476Sdelphij * @param dc the devclass to search 1020171476Sdelphij * @param unit the unit number to search for 1021171476Sdelphij * 1022171476Sdelphij * @returns the softc field of the device with the given 1023171476Sdelphij * unit number or @c NULL if there is no such 1024171476Sdelphij * device 1025171476Sdelphij */ 1026171476Sdelphijvoid * 1027171476Sdelphijdevclass_get_softc(devclass_t dc, int unit) 1028171476Sdelphij{ 1029171476Sdelphij device_t dev; 1030171476Sdelphij 1031171476Sdelphij dev = devclass_get_device(dc, unit); 1032171476Sdelphij if (!dev) 1033171476Sdelphij return (NULL); 1034171476Sdelphij 1035171476Sdelphij return (device_get_softc(dev)); 1036171476Sdelphij} 1037171476Sdelphij 1038171476Sdelphij/** 1039171476Sdelphij * @brief Get a list of devices in the devclass 1040171476Sdelphij * 1041171476Sdelphij * An array containing a list of all the devices in the given devclass 1042171476Sdelphij * is allocated and returned in @p *devlistp. The number of devices 1043171476Sdelphij * in the array is returned in @p *devcountp. The caller should free 1044171476Sdelphij * the array using @c free(p, M_TEMP). 1045171476Sdelphij * 1046171476Sdelphij * @param dc the devclass to examine 1047171476Sdelphij * @param devlistp points at location for array pointer return 1048171476Sdelphij * value 1049171476Sdelphij * @param devcountp points at location for array size return value 1050171476Sdelphij * 1051171476Sdelphij * @retval 0 success 1052171476Sdelphij * @retval ENOMEM the array allocation failed 1053171476Sdelphij */ 1054171476Sdelphijint 1055171476Sdelphijdevclass_get_devices(devclass_t dc, device_t **devlistp, int *devcountp) 1056171476Sdelphij{ 1057171476Sdelphij int i; 1058171476Sdelphij int count; 1059171476Sdelphij device_t *list; 1060171476Sdelphij 1061171476Sdelphij count = 0; 1062171476Sdelphij for (i = 0; i < dc->maxunit; i++) 1063171476Sdelphij if (dc->devices[i]) 1064171476Sdelphij count++; 1065171476Sdelphij 1066171476Sdelphij list = malloc(count * sizeof(device_t), M_TEMP, M_NOWAIT|M_ZERO); 1067171476Sdelphij if (!list) 1068171476Sdelphij return (ENOMEM); 1069171476Sdelphij 1070171476Sdelphij count = 0; 1071171476Sdelphij for (i = 0; i < dc->maxunit; i++) { 1072171476Sdelphij if (dc->devices[i]) { 1073171476Sdelphij list[count] = dc->devices[i]; 1074171476Sdelphij count++; 1075171476Sdelphij } 1076171476Sdelphij } 1077171476Sdelphij 1078171476Sdelphij *devlistp = list; 1079171476Sdelphij *devcountp = count; 1080171476Sdelphij 1081171476Sdelphij return (0); 1082171476Sdelphij} 1083171476Sdelphij 1084171476Sdelphij/** 1085171476Sdelphij * @brief Get the maximum unit number used in a devclass 1086171476Sdelphij * 1087171476Sdelphij * @param dc the devclass to examine 1088171476Sdelphij */ 1089171476Sdelphijint 1090171476Sdelphijdevclass_get_maxunit(devclass_t dc) 1091171476Sdelphij{ 1092171476Sdelphij return (dc->maxunit); 1093171476Sdelphij} 1094171476Sdelphij 1095171476Sdelphij/** 1096171476Sdelphij * @brief Find a free unit number in a devclass 1097171476Sdelphij * 1098171476Sdelphij * This function searches for the first unused unit number greater 1099171476Sdelphij * that or equal to @p unit. 1100171476Sdelphij * 1101171476Sdelphij * @param dc the devclass to examine 1102171476Sdelphij * @param unit the first unit number to check 1103171476Sdelphij */ 1104171476Sdelphijint 1105171476Sdelphijdevclass_find_free_unit(devclass_t dc, int unit) 1106171476Sdelphij{ 1107171476Sdelphij if (dc == NULL) 1108171476Sdelphij return (unit); 1109171476Sdelphij while (unit < dc->maxunit && dc->devices[unit] != NULL) 1110171476Sdelphij unit++; 1111171476Sdelphij return (unit); 1112171476Sdelphij} 1113171476Sdelphij 1114171476Sdelphij/** 1115171476Sdelphij * @brief Set the parent of a devclass 1116171476Sdelphij * 1117171476Sdelphij * The parent class is normally initialised automatically by 1118171476Sdelphij * DRIVER_MODULE(). 1119171476Sdelphij * 1120171476Sdelphij * @param dc the devclass to edit 1121171476Sdelphij * @param pdc the new parent devclass 1122171476Sdelphij */ 1123171476Sdelphijvoid 1124171476Sdelphijdevclass_set_parent(devclass_t dc, devclass_t pdc) 1125171476Sdelphij{ 1126171476Sdelphij dc->parent = pdc; 1127171476Sdelphij} 1128171476Sdelphij 1129171476Sdelphij/** 1130171476Sdelphij * @brief Get the parent of a devclass 1131171476Sdelphij * 1132171476Sdelphij * @param dc the devclass to examine 1133171476Sdelphij */ 1134171476Sdelphijdevclass_t 1135171476Sdelphijdevclass_get_parent(devclass_t dc) 1136171476Sdelphij{ 1137171476Sdelphij return (dc->parent); 1138171476Sdelphij} 1139171476Sdelphij 1140171476Sdelphijstruct sysctl_ctx_list * 1141171476Sdelphijdevclass_get_sysctl_ctx(devclass_t dc) 1142171476Sdelphij{ 1143171476Sdelphij return (&dc->sysctl_ctx); 1144171476Sdelphij} 1145171476Sdelphij 1146171476Sdelphijstruct sysctl_oid * 1147171476Sdelphijdevclass_get_sysctl_tree(devclass_t dc) 1148171476Sdelphij{ 1149171476Sdelphij return (dc->sysctl_tree); 1150171476Sdelphij} 1151171476Sdelphij 1152171476Sdelphij/** 1153171476Sdelphij * @internal 1154171476Sdelphij * @brief Allocate a unit number 1155171476Sdelphij * 1156171476Sdelphij * On entry, @p *unitp is the desired unit number (or @c -1 if any 1157171476Sdelphij * will do). The allocated unit number is returned in @p *unitp. 1158171476Sdelphij 1159171476Sdelphij * @param dc the devclass to allocate from 1160171476Sdelphij * @param unitp points at the location for the allocated unit 1161171476Sdelphij * number 1162171476Sdelphij * 1163171476Sdelphij * @retval 0 success 1164171476Sdelphij * @retval EEXIST the requested unit number is already allocated 1165171476Sdelphij * @retval ENOMEM memory allocation failure 1166171476Sdelphij */ 1167171476Sdelphijstatic int 1168171476Sdelphijdevclass_alloc_unit(devclass_t dc, int *unitp) 1169171476Sdelphij{ 1170171476Sdelphij int unit = *unitp; 1171171476Sdelphij 1172171476Sdelphij PDEBUG(("unit %d in devclass %s", unit, DEVCLANAME(dc))); 1173171476Sdelphij 1174171476Sdelphij /* If we were given a wired unit number, check for existing device */ 1175171476Sdelphij /* XXX imp XXX */ 1176171476Sdelphij if (unit != -1) { 1177171476Sdelphij if (unit >= 0 && unit < dc->maxunit && 1178169445Sroberto dc->devices[unit] != NULL) { 1179169445Sroberto if (bootverbose) 1180169445Sroberto printf("%s: %s%d already exists; skipping it\n", 1181169026Semax dc->name, dc->name, *unitp); 1182169026Semax return (EEXIST); 1183168916Sbrueffer } 1184168916Sbrueffer } else { 1185168796Sthompsa /* Unwired device, find the next available slot for it */ 1186168796Sthompsa unit = 0; 1187168544Spjd while (unit < dc->maxunit && dc->devices[unit] != NULL) 1188168544Spjd unit++; 1189167980Sdelphij } 1190167980Sdelphij 1191167699Sdelphij /* 1192167699Sdelphij * We've selected a unit beyond the length of the table, so let's 1193176956Santoine * extend the table to make room for all units up to and including 1194176956Santoine * this one. 1195176956Santoine */ 1196167137Sbms if (unit >= dc->maxunit) { 1197167137Sbms device_t *newlist; 1198170190Sru int newsize; 1199166981Sru 1200166981Sru newsize = roundup((unit + 1), MINALLOCSIZE / sizeof(device_t)); 1201170192Sru newlist = malloc(sizeof(device_t) * newsize, M_BUS, M_NOWAIT); 1202170218Struckman if (!newlist) 1203166668Sbrueffer return (ENOMEM); 1204166668Sbrueffer bcopy(dc->devices, newlist, sizeof(device_t) * dc->maxunit); 1205166389Srafan bzero(newlist + dc->maxunit, 1206166389Srafan sizeof(device_t) * (newsize - dc->maxunit)); 1207166389Srafan if (dc->devices) 1208172882Sru free(dc->devices, M_BUS); 1209172882Sru dc->devices = newlist; 1210172882Sru dc->maxunit = newsize; 1211172882Sru } 1212170190Sru PDEBUG(("now: unit %d in devclass %s", unit, DEVCLANAME(dc))); 1213170190Sru 1214170190Sru *unitp = unit; 1215170190Sru return (0); 1216172882Sru} 1217172882Sru 1218172882Sru/** 1219170190Sru * @internal 1220166308Sphk * @brief Add a device to a devclass 1221166308Sphk * 1222170192Sru * A unit number is allocated for the device (using the device's 1223170192Sru * preferred unit number if any) and the device is registered in the 1224166246Speter * devclass. This allows the device to be looked up by its unit 1225166246Speter * number, e.g. by decoding a dev_t minor number. 1226166246Speter * 1227166246Speter * @param dc the devclass to add to 1228166246Speter * @param dev the device to add 1229164796Spiso * 1230164796Spiso * @retval 0 success 1231164796Spiso * @retval EEXIST the requested unit number is already allocated 1232164796Spiso * @retval ENOMEM memory allocation failure 1233164796Spiso */ 1234164796Spisostatic int 1235164796Spisodevclass_add_device(devclass_t dc, device_t dev) 1236164796Spiso{ 1237164796Spiso int buflen, error; 1238166672Sbrueffer 1239164796Spiso PDEBUG(("%s in devclass %s", DEVICENAME(dev), DEVCLANAME(dc))); 1240164796Spiso 1241164796Spiso buflen = snprintf(NULL, 0, "%s%d$", dc->name, dev->unit); 1242164796Spiso if (buflen < 0) 1243164796Spiso return (ENOMEM); 1244164796Spiso dev->nameunit = malloc(buflen, M_BUS, M_NOWAIT|M_ZERO); 1245164796Spiso if (!dev->nameunit) 1246164796Spiso return (ENOMEM); 1247165726Skientzle 1248165726Skientzle if ((error = devclass_alloc_unit(dc, &dev->unit)) != 0) { 1249164610Simp free(dev->nameunit, M_BUS); 1250164610Simp dev->nameunit = NULL; 1251164537Srodrigc return (error); 1252164537Srodrigc } 1253164537Srodrigc dc->devices[dev->unit] = dev; 1254164537Srodrigc dev->devclass = dc; 1255164537Srodrigc snprintf(dev->nameunit, buflen, "%s%d", dc->name, dev->unit); 1256164537Srodrigc 1257164537Srodrigc return (0); 1258170190Sru} 1259170190Sru 1260170190Sru/** 1261170190Sru * @internal 1262170190Sru * @brief Delete a device from a devclass 1263170190Sru * 1264164537Srodrigc * The device is removed from the devclass's device list and its unit 1265164537Srodrigc * number is freed. 1266164537Srodrigc 1267164537Srodrigc * @param dc the devclass to delete from 1268164537Srodrigc * @param dev the device to delete 1269164537Srodrigc * 1270164344Sbrueffer * @retval 0 success 1271164344Sbrueffer */ 1272170220Struckmanstatic int 1273170220Struckmandevclass_delete_device(devclass_t dc, device_t dev) 1274164088Smarcel{ 1275164088Smarcel if (!dc || !dev) 1276164088Smarcel return (0); 1277164088Smarcel 1278163570Sru PDEBUG(("%s in devclass %s", DEVICENAME(dev), DEVCLANAME(dc))); 1279163570Sru 1280162837Sdelphij if (dev->devclass != dc || dc->devices[dev->unit] != dev) 1281162837Sdelphij panic("devclass_delete_device: inconsistent device class"); 1282162780Sbms dc->devices[dev->unit] = NULL; 1283162780Sbms if (dev->flags & DF_WILDCARD) 1284162780Sbms dev->unit = -1; 1285162780Sbms dev->devclass = NULL; 1286162780Sbms free(dev->nameunit, M_BUS); 1287162780Sbms dev->nameunit = NULL; 1288162780Sbms 1289162780Sbms return (0); 1290162780Sbms} 1291162598Ssimon 1292162598Ssimon/** 1293162598Ssimon * @internal 1294162716Sdelphij * @brief Make a new device and add it as a child of @p parent 1295162716Sdelphij * 1296161529Sflz * @param parent the parent of the new device 1297161529Sflz * @param name the devclass name of the new device or @c NULL 1298161529Sflz * to leave the devclass unspecified 1299170192Sru * @parem unit the unit number of the new device of @c -1 to 1300170192Sru * leave the unit number unspecified 1301170192Sru * 1302170192Sru * @returns the new device 1303170192Sru */ 1304170192Srustatic device_t 1305170192Srumake_device(device_t parent, const char *name, int unit) 1306170192Sru{ 1307170192Sru device_t dev; 1308170192Sru devclass_t dc; 1309170192Sru 1310170192Sru PDEBUG(("%s at %s as unit %d", name, DEVICENAME(parent), unit)); 1311170192Sru 1312160983Sbrooks if (name) { 1313160983Sbrooks dc = devclass_find_internal(name, 0, TRUE); 1314170255Struckman if (!dc) { 1315170255Struckman printf("make_device: can't find device class %s\n", 1316170255Struckman name); 1317170255Struckman return (NULL); 1318158687Sphk } 1319158687Sphk } else { 1320158687Sphk dc = NULL; 1321158687Sphk } 1322158687Sphk 1323158687Sphk dev = malloc(sizeof(struct device), M_BUS, M_NOWAIT|M_ZERO); 1324158687Sphk if (!dev) 1325158687Sphk return (NULL); 1326158687Sphk 1327158687Sphk dev->parent = parent; 1328158687Sphk TAILQ_INIT(&dev->children); 1329158687Sphk kobj_init((kobj_t) dev, &null_class); 1330158687Sphk dev->driver = NULL; 1331158687Sphk dev->devclass = NULL; 1332158687Sphk dev->unit = unit; 1333158687Sphk dev->nameunit = NULL; 1334158687Sphk dev->desc = NULL; 1335158687Sphk dev->busy = 0; 1336158687Sphk dev->devflags = 0; 1337158687Sphk dev->flags = DF_ENABLED; 1338158687Sphk dev->order = 0; 1339158687Sphk if (unit == -1) 1340158687Sphk dev->flags |= DF_WILDCARD; 1341158687Sphk if (name) { 1342158687Sphk dev->flags |= DF_FIXEDCLASS; 1343158687Sphk if (devclass_add_device(dc, dev)) { 1344158687Sphk kobj_delete((kobj_t) dev, M_BUS); 1345158687Sphk return (NULL); 1346158687Sphk } 1347158687Sphk } 1348158687Sphk dev->ivars = NULL; 1349158687Sphk dev->softc = NULL; 1350158687Sphk 1351158687Sphk dev->state = DS_NOTPRESENT; 1352158687Sphk 1353158687Sphk TAILQ_INSERT_TAIL(&bus_data_devices, dev, devlink); 1354158687Sphk bus_data_generation_update(); 1355158687Sphk 1356158687Sphk return (dev); 1357158687Sphk} 1358158687Sphk 1359158687Sphk/** 1360158687Sphk * @internal 1361158687Sphk * @brief Print a description of a device. 1362158687Sphk */ 1363158687Sphkstatic int 1364158687Sphkdevice_print_child(device_t dev, device_t child) 1365158687Sphk{ 1366158687Sphk int retval = 0; 1367158687Sphk 1368158687Sphk if (device_is_alive(child)) 1369158687Sphk retval += BUS_PRINT_CHILD(dev, child); 1370158687Sphk else 1371158618Smaxim retval += device_printf(child, " not found\n"); 1372158618Smaxim 1373158618Smaxim return (retval); 1374158512Smlaier} 1375158512Smlaier 1376158512Smlaier/** 1377158512Smlaier * @brief Create a new device 1378158512Smlaier * 1379158754Smarcel * This creates a new device and adds it as a child of an existing 1380158754Smarcel * parent device. The new device will be added after the last existing 1381157221Ssimon * child with order zero. 1382157221Ssimon * 1383156676Sharti * @param dev the device which will be the parent of the 1384156676Sharti * new child device 1385170190Sru * @param name devclass name for new device or @c NULL if not 1386170190Sru * specified 1387170190Sru * @param unit unit number for new device or @c -1 if not 1388170190Sru * specified 1389170190Sru * 1390170190Sru * @returns the new device 1391170190Sru */ 1392170190Srudevice_t 1393153662Sjhbdevice_add_child(device_t dev, const char *name, int unit) 1394153662Sjhb{ 1395153430Siedowse return (device_add_child_ordered(dev, 0, name, unit)); 1396153430Siedowse} 1397153430Siedowse 1398153430Siedowse/** 1399153430Siedowse * @brief Create a new device 1400151845Syar * 1401151845Syar * This creates a new device and adds it as a child of an existing 1402151271Spjd * parent device. The new device will be added after the last existing 1403151271Spjd * child with the same order. 1404162025Smatusita * 1405162025Smatusita * @param dev the device which will be the parent of the 1406162025Smatusita * new child device 1407162025Smatusita * @param order a value which is used to partially sort the 1408150676Smlaier * children of @p dev - devices created using 1409150677Smlaier * lower values of @p order appear first in @p 1410150002Snetchild * dev's list of children 1411150002Snetchild * @param name devclass name for new device or @c NULL if not 1412150002Snetchild * specified 1413150002Snetchild * @param unit unit number for new device or @c -1 if not 1414149454Sglebius * specified 1415148808Sru * 1416148808Sru * @returns the new device 1417148825Snetchild */ 1418148825Snetchilddevice_t 1419148356Sdougbdevice_add_child_ordered(device_t dev, int order, const char *name, int unit) 1420148356Sdougb{ 1421148572Snetchild device_t child; 1422170220Struckman device_t place; 1423170220Struckman 1424170220Struckman PDEBUG(("%s at %s with order %d as unit %d", 1425170220Struckman name, DEVICENAME(dev), order, unit)); 1426170220Struckman 1427148330Snetchild child = make_device(dev, name, unit); 1428148330Snetchild if (child == NULL) 1429148330Snetchild return (child); 1430148330Snetchild child->order = order; 1431148572Snetchild 1432148572Snetchild TAILQ_FOREACH(place, &dev->children, link) { 1433149105Simp if (place->order > order) 1434148572Snetchild break; 1435148572Snetchild } 1436148572Snetchild 1437172026Syar if (place) { 1438172026Syar /* 1439172026Syar * The device 'place' is the first device whose order is 1440172026Syar * greater than the new child. 1441148572Snetchild */ 1442148572Snetchild TAILQ_INSERT_BEFORE(place, child, link); 1443148572Snetchild } else { 1444148572Snetchild /* 1445148572Snetchild * The new child's order is greater or equal to the order of 1446148572Snetchild * any existing device. Add the child to the tail of the list. 1447148572Snetchild */ 1448148572Snetchild TAILQ_INSERT_TAIL(&dev->children, child, link); 1449148572Snetchild } 1450148572Snetchild 1451148572Snetchild bus_data_generation_update(); 1452153939Snetchild return (child); 1453153939Snetchild} 1454153939Snetchild 1455153939Snetchild/** 1456148330Snetchild * @brief Delete a device 1457148330Snetchild * 1458148423Sdougb * This function deletes a device along with all of its children. If 1459148423Sdougb * the device currently has a driver attached to it, the device is 1460148330Snetchild * detached first using device_detach(). 1461148330Snetchild * 1462148330Snetchild * @param dev the parent device 1463148330Snetchild * @param child the device to delete 1464148572Snetchild * 1465148572Snetchild * @retval 0 success 1466148353Sdougb * @retval non-zero a unit error code describing the error 1467148353Sdougb */ 1468149105Simpint 1469149105Simpdevice_delete_child(device_t dev, device_t child) 1470148572Snetchild{ 1471148572Snetchild int error; 1472172026Syar device_t grandchild; 1473149105Simp 1474148572Snetchild PDEBUG(("%s from %s", DEVICENAME(child), DEVICENAME(dev))); 1475155813Snetchild 1476155813Snetchild /* remove children first */ 1477155813Snetchild while ( (grandchild = TAILQ_FIRST(&child->children)) ) { 1478155813Snetchild error = device_delete_child(child, grandchild); 1479148330Snetchild if (error) 1480148330Snetchild return (error); 1481148330Snetchild } 1482163991Strhodes 1483163991Strhodes if ((error = device_detach(child)) != 0) 1484163991Strhodes return (error); 1485163991Strhodes if (child->devclass) 1486163991Strhodes devclass_delete_device(child->devclass, child); 1487163991Strhodes TAILQ_REMOVE(&dev->children, child, link); 1488163991Strhodes TAILQ_REMOVE(&bus_data_devices, child, devlink); 1489163991Strhodes kobj_delete((kobj_t) child, M_BUS); 1490163991Strhodes 1491163991Strhodes bus_data_generation_update(); 1492163991Strhodes return (0); 1493148330Snetchild} 1494148330Snetchild 1495148330Snetchild/** 1496148330Snetchild * @brief Find a device given a unit number 1497155813Snetchild * 1498148330Snetchild * This is similar to devclass_get_devices() but only searches for 1499148330Snetchild * devices which have @p dev as a parent. 1500148330Snetchild * 1501148330Snetchild * @param dev the parent device to search 1502148330Snetchild * @param unit the unit number to search for 1503148330Snetchild * 1504148543Snetchild * @returns the device with the given unit number or @c 1505148543Snetchild * NULL if there is no such device 1506148543Snetchild */ 1507148543Snetchilddevice_t 1508148543Snetchilddevice_find_child(device_t dev, const char *classname, int unit) 1509148543Snetchild{ 1510148543Snetchild devclass_t dc; 1511148543Snetchild device_t child; 1512148543Snetchild 1513148543Snetchild dc = devclass_find(classname); 1514148543Snetchild if (!dc) 1515148543Snetchild return (NULL); 1516148543Snetchild 1517148543Snetchild child = devclass_get_device(dc, unit); 1518148543Snetchild if (child && child->parent == dev) 1519148543Snetchild return (child); 1520148543Snetchild return (NULL); 1521148543Snetchild} 1522148543Snetchild 1523148543Snetchild/** 1524148543Snetchild * @internal 1525148572Snetchild */ 1526148572Snetchildstatic driverlink_t 1527148572Snetchildfirst_matching_driver(devclass_t dc, device_t dev) 1528148572Snetchild{ 1529148572Snetchild if (dev->devclass) 1530148572Snetchild return (devclass_find_driver_internal(dc, dev->devclass->name)); 1531148572Snetchild return (TAILQ_FIRST(&dc->drivers)); 1532148572Snetchild} 1533148572Snetchild 1534148572Snetchild/** 1535148572Snetchild * @internal 1536148572Snetchild */ 1537148572Snetchildstatic driverlink_t 1538148572Snetchildnext_matching_driver(devclass_t dc, device_t dev, driverlink_t last) 1539148572Snetchild{ 1540148572Snetchild if (dev->devclass) { 1541148572Snetchild driverlink_t dl; 1542148572Snetchild for (dl = TAILQ_NEXT(last, link); dl; dl = TAILQ_NEXT(dl, link)) 1543148572Snetchild if (!strcmp(dev->devclass->name, dl->driver->name)) 1544148572Snetchild return (dl); 1545148572Snetchild return (NULL); 1546148572Snetchild } 1547148572Snetchild return (TAILQ_NEXT(last, link)); 1548148572Snetchild} 1549148572Snetchild 1550148572Snetchild/** 1551148572Snetchild * @internal 1552148572Snetchild */ 1553148572Snetchildstatic int 1554148572Snetchilddevice_probe_child(device_t dev, device_t child) 1555148572Snetchild{ 1556148572Snetchild devclass_t dc; 1557148572Snetchild driverlink_t best = 0; 1558148572Snetchild driverlink_t dl; 1559148572Snetchild int result, pri = 0; 1560148572Snetchild int hasclass = (child->devclass != 0); 1561148572Snetchild 1562148572Snetchild GIANT_REQUIRED; 1563148572Snetchild 1564148572Snetchild dc = dev->devclass; 1565148572Snetchild if (!dc) 1566148572Snetchild panic("device_probe_child: parent device has no devclass"); 1567148572Snetchild 1568148572Snetchild /* 1569148572Snetchild * If the state is already probed, then return. However, don't 1570148572Snetchild * return if we can rebid this object. 1571148572Snetchild */ 1572148572Snetchild if (child->state == DS_ALIVE && (child->flags & DF_REBID) == 0) 1573148572Snetchild return (0); 1574148572Snetchild 1575148572Snetchild for (; dc; dc = dc->parent) { 1576148572Snetchild for (dl = first_matching_driver(dc, child); 1577148572Snetchild dl; 1578148572Snetchild dl = next_matching_driver(dc, child, dl)) { 1579148572Snetchild PDEBUG(("Trying %s", DRIVERNAME(dl->driver))); 1580148572Snetchild device_set_driver(child, dl->driver); 1581148572Snetchild if (!hasclass) 1582148572Snetchild device_set_devclass(child, dl->driver->name); 1583148572Snetchild 1584148572Snetchild /* Fetch any flags for the device before probing. */ 1585148572Snetchild resource_int_value(dl->driver->name, child->unit, 1586148572Snetchild "flags", &child->devflags); 1587148572Snetchild 1588148572Snetchild result = DEVICE_PROBE(child); 1589148572Snetchild 1590148572Snetchild /* Reset flags and devclass before the next probe. */ 1591148572Snetchild child->devflags = 0; 1592148572Snetchild if (!hasclass) 1593148572Snetchild device_set_devclass(child, 0); 1594148572Snetchild 1595148572Snetchild /* 1596148572Snetchild * If the driver returns SUCCESS, there can be 1597148572Snetchild * no higher match for this device. 1598148572Snetchild */ 1599148572Snetchild if (result == 0) { 1600148572Snetchild best = dl; 1601148572Snetchild pri = 0; 1602148572Snetchild break; 1603148572Snetchild } 1604148572Snetchild 1605148572Snetchild /* 1606148572Snetchild * The driver returned an error so it 1607148572Snetchild * certainly doesn't match. 1608148572Snetchild */ 1609148572Snetchild if (result > 0) { 1610148572Snetchild device_set_driver(child, 0); 1611148572Snetchild continue; 1612148572Snetchild } 1613148572Snetchild 1614148572Snetchild /* 1615148572Snetchild * A priority lower than SUCCESS, remember the 1616148572Snetchild * best matching driver. Initialise the value 1617148572Snetchild * of pri for the first match. 1618148572Snetchild */ 1619148572Snetchild if (best == 0 || result > pri) { 1620148572Snetchild best = dl; 1621148572Snetchild pri = result; 1622148572Snetchild continue; 1623148572Snetchild } 1624148572Snetchild } 1625148572Snetchild /* 1626148572Snetchild * If we have an unambiguous match in this devclass, 1627148572Snetchild * don't look in the parent. 1628148572Snetchild */ 1629148572Snetchild if (best && pri == 0) 1630148572Snetchild break; 1631148572Snetchild } 1632148572Snetchild 1633148330Snetchild /* 1634148330Snetchild * If we found a driver, change state and initialise the devclass. 1635148330Snetchild */ 1636148330Snetchild /* XXX What happens if we rebid and got no best? */ 1637148330Snetchild if (best) { 1638190613Strhodes /* 1639190613Strhodes * If this device was atached, and we were asked to 1640148572Snetchild * rescan, and it is a different driver, then we have 1641148572Snetchild * to detach the old driver and reattach this new one. 1642148572Snetchild * Note, we don't have to check for DF_REBID here 1643148572Snetchild * because if the state is > DS_ALIVE, we know it must 1644148572Snetchild * be. 1645148572Snetchild * 1646177625Sremko * This assumes that all DF_REBID drivers can have 1647177625Sremko * their probe routine called at any time and that 1648177625Sremko * they are idempotent as well as completely benign in 1649148572Snetchild * normal operations. 1650148572Snetchild * 1651148572Snetchild * We also have to make sure that the detach 1652148572Snetchild * succeeded, otherwise we fail the operation (or 1653149113Simp * maybe it should just fail silently? I'm torn). 1654149113Simp */ 1655149113Simp if (child->state > DS_ALIVE && best->driver != child->driver) 1656149113Simp if ((result = device_detach(dev)) != 0) 1657149113Simp return (result); 1658149113Simp 1659149113Simp /* Set the winning driver, devclass, and flags. */ 1660148572Snetchild if (!child->devclass) 1661148572Snetchild device_set_devclass(child, best->driver->name); 1662148572Snetchild device_set_driver(child, best->driver); 1663148572Snetchild resource_int_value(best->driver->name, child->unit, 1664148572Snetchild "flags", &child->devflags); 1665149105Simp 1666148572Snetchild if (pri < 0) { 1667148572Snetchild /* 1668148572Snetchild * A bit bogus. Call the probe method again to make 1669148572Snetchild * sure that we have the right description. 1670148572Snetchild */ 1671148572Snetchild DEVICE_PROBE(child); 1672148572Snetchild#if 0 1673148572Snetchild child->flags |= DF_REBID; 1674170220Struckman#endif 1675170220Struckman } else 1676156385Syar child->flags &= ~DF_REBID; 1677156385Syar child->state = DS_ALIVE; 1678148330Snetchild 1679148330Snetchild bus_data_generation_update(); 1680148330Snetchild return (0); 1681148330Snetchild } 1682148330Snetchild 1683148330Snetchild return (ENXIO); 1684148330Snetchild} 1685148330Snetchild 1686148330Snetchild/** 1687148330Snetchild * @brief Return the parent of a device 1688148330Snetchild */ 1689148330Snetchilddevice_t 1690148330Snetchilddevice_get_parent(device_t dev) 1691148330Snetchild{ 1692148330Snetchild return (dev->parent); 1693148330Snetchild} 1694148330Snetchild 1695148330Snetchild/** 1696148330Snetchild * @brief Get a list of children of a device 1697148330Snetchild * 1698148330Snetchild * An array containing a list of all the children of the given device 1699148572Snetchild * is allocated and returned in @p *devlistp. The number of devices 1700148572Snetchild * in the array is returned in @p *devcountp. The caller should free 1701149105Simp * the array using @c free(p, M_TEMP). 1702148572Snetchild * 1703148572Snetchild * @param dev the device to examine 1704148572Snetchild * @param devlistp points at location for array pointer return 1705148572Snetchild * value 1706148572Snetchild * @param devcountp points at location for array size return value 1707148572Snetchild * 1708148572Snetchild * @retval 0 success 1709155279Savatar * @retval ENOMEM the array allocation failed 1710155279Savatar */ 1711155279Savatarint 1712155279Savatardevice_get_children(device_t dev, device_t **devlistp, int *devcountp) 1713148572Snetchild{ 1714148572Snetchild int count; 1715148572Snetchild device_t child; 1716148330Snetchild device_t *list; 1717148330Snetchild 1718148330Snetchild count = 0; 1719148330Snetchild TAILQ_FOREACH(child, &dev->children, link) { 1720148330Snetchild count++; 1721148330Snetchild } 1722148330Snetchild 1723148330Snetchild list = malloc(count * sizeof(device_t), M_TEMP, M_NOWAIT|M_ZERO); 1724148330Snetchild if (!list) 1725148330Snetchild return (ENOMEM); 1726148330Snetchild 1727148330Snetchild count = 0; 1728148330Snetchild TAILQ_FOREACH(child, &dev->children, link) { 1729148330Snetchild list[count] = child; 1730148330Snetchild count++; 1731148330Snetchild } 1732149105Simp 1733149105Simp *devlistp = list; 1734148572Snetchild *devcountp = count; 1735170219Struckman 1736148572Snetchild return (0); 1737148572Snetchild} 1738148572Snetchild 1739148330Snetchild/** 1740148330Snetchild * @brief Return the current driver for the device or @c NULL if there 1741148330Snetchild * is no driver currently attached 1742148330Snetchild */ 1743148330Snetchilddriver_t * 1744148330Snetchilddevice_get_driver(device_t dev) 1745148330Snetchild{ 1746148330Snetchild return (dev->driver); 1747148330Snetchild} 1748148330Snetchild 1749148330Snetchild/** 1750148330Snetchild * @brief Return the current devclass for the device or @c NULL if 1751148330Snetchild * there is none. 1752148330Snetchild */ 1753148330Snetchilddevclass_t 1754148330Snetchilddevice_get_devclass(device_t dev) 1755148330Snetchild{ 1756148330Snetchild return (dev->devclass); 1757148330Snetchild} 1758148330Snetchild 1759148330Snetchild/** 1760148330Snetchild * @brief Return the name of the device's devclass or @c NULL if there 1761148330Snetchild * is none. 1762148572Snetchild */ 1763148572Snetchildconst char * 1764148572Snetchilddevice_get_name(device_t dev) 1765148572Snetchild{ 1766148572Snetchild if (dev != NULL && dev->devclass) 1767148572Snetchild return (devclass_get_name(dev->devclass)); 1768148572Snetchild return (NULL); 1769148572Snetchild} 1770148572Snetchild 1771148572Snetchild/** 1772148572Snetchild * @brief Return a string containing the device's devclass name 1773148572Snetchild * followed by an ascii representation of the device's unit number 1774148572Snetchild * (e.g. @c "foo2"). 1775148572Snetchild */ 1776148572Snetchildconst char * 1777148572Snetchilddevice_get_nameunit(device_t dev) 1778148572Snetchild{ 1779148572Snetchild return (dev->nameunit); 1780148572Snetchild} 1781148572Snetchild 1782148572Snetchild/** 1783148572Snetchild * @brief Return the device's unit number. 1784148572Snetchild */ 1785148572Snetchildint 1786148572Snetchilddevice_get_unit(device_t dev) 1787148572Snetchild{ 1788148572Snetchild return (dev->unit); 1789148572Snetchild} 1790148572Snetchild 1791148572Snetchild/** 1792148572Snetchild * @brief Return the device's description string 1793148572Snetchild */ 1794148572Snetchildconst char * 1795148572Snetchilddevice_get_desc(device_t dev) 1796148572Snetchild{ 1797148572Snetchild return (dev->desc); 1798148572Snetchild} 1799148572Snetchild 1800148572Snetchild/** 1801148572Snetchild * @brief Return the device's flags 1802148572Snetchild */ 1803148572Snetchildu_int32_t 1804148572Snetchilddevice_get_flags(device_t dev) 1805148572Snetchild{ 1806148572Snetchild return (dev->devflags); 1807148572Snetchild} 1808148572Snetchild 1809148572Snetchildstruct sysctl_ctx_list * 1810148572Snetchilddevice_get_sysctl_ctx(device_t dev) 1811148572Snetchild{ 1812148572Snetchild return (&dev->sysctl_ctx); 1813148572Snetchild} 1814148572Snetchild 1815148572Snetchildstruct sysctl_oid * 1816148572Snetchilddevice_get_sysctl_tree(device_t dev) 1817148572Snetchild{ 1818148572Snetchild return (dev->sysctl_tree); 1819148572Snetchild} 1820148572Snetchild 1821148572Snetchild/** 1822148572Snetchild * @brief Print the name of the device followed by a colon and a space 1823148572Snetchild * 1824148572Snetchild * @returns the number of characters printed 1825148572Snetchild */ 1826148572Snetchildint 1827148572Snetchilddevice_print_prettyname(device_t dev) 1828148572Snetchild{ 1829148572Snetchild const char *name = device_get_name(dev); 1830148572Snetchild 1831148572Snetchild if (name == 0) 1832148572Snetchild return (printf("unknown: ")); 1833148572Snetchild return (printf("%s%d: ", name, device_get_unit(dev))); 1834148572Snetchild} 1835148572Snetchild 1836148572Snetchild/** 1837148572Snetchild * @brief Print the name of the device followed by a colon, a space 1838148572Snetchild * and the result of calling vprintf() with the value of @p fmt and 1839148572Snetchild * the following arguments. 1840148572Snetchild * 1841148572Snetchild * @returns the number of characters printed 1842148572Snetchild */ 1843148572Snetchildint 1844148572Snetchilddevice_printf(device_t dev, const char * fmt, ...) 1845148572Snetchild{ 1846148572Snetchild va_list ap; 1847148572Snetchild int retval; 1848148572Snetchild 1849148572Snetchild retval = device_print_prettyname(dev); 1850148572Snetchild va_start(ap, fmt); 1851148572Snetchild retval += vprintf(fmt, ap); 1852148572Snetchild va_end(ap); 1853148572Snetchild return (retval); 1854148572Snetchild} 1855148572Snetchild 1856148572Snetchild/** 1857148572Snetchild * @internal 1858148572Snetchild */ 1859148572Snetchildstatic void 1860148572Snetchilddevice_set_desc_internal(device_t dev, const char* desc, int copy) 1861149105Simp{ 1862149105Simp if (dev->desc && (dev->flags & DF_DESCMALLOCED)) { 1863149105Simp free(dev->desc, M_BUS); 1864149105Simp dev->flags &= ~DF_DESCMALLOCED; 1865148572Snetchild dev->desc = NULL; 1866164619Snetchild } 1867164619Snetchild 1868148572Snetchild if (copy && desc) { 1869148572Snetchild dev->desc = malloc(strlen(desc) + 1, M_BUS, M_NOWAIT); 1870148572Snetchild if (dev->desc) { 1871148572Snetchild strcpy(dev->desc, desc); 1872148572Snetchild dev->flags |= DF_DESCMALLOCED; 1873148572Snetchild } 1874148572Snetchild } else { 1875148572Snetchild /* Avoid a -Wcast-qual warning */ 1876148572Snetchild dev->desc = (char *)(uintptr_t) desc; 1877148572Snetchild } 1878148572Snetchild 1879148572Snetchild bus_data_generation_update(); 1880148572Snetchild} 1881148572Snetchild 1882148572Snetchild/** 1883148572Snetchild * @brief Set the device's description 1884148572Snetchild * 1885148572Snetchild * The value of @c desc should be a string constant that will not 1886148572Snetchild * change (at least until the description is changed in a subsequent 1887148572Snetchild * call to device_set_desc() or device_set_desc_copy()). 1888148572Snetchild */ 1889148572Snetchildvoid 1890148572Snetchilddevice_set_desc(device_t dev, const char* desc) 1891148572Snetchild{ 1892148572Snetchild device_set_desc_internal(dev, desc, FALSE); 1893148572Snetchild} 1894148572Snetchild 1895148572Snetchild/** 1896148572Snetchild * @brief Set the device's description 1897148572Snetchild * 1898148572Snetchild * The string pointed to by @c desc is copied. Use this function if 1899148572Snetchild * the device description is generated, (e.g. with sprintf()). 1900148572Snetchild */ 1901148572Snetchildvoid 1902148572Snetchilddevice_set_desc_copy(device_t dev, const char* desc) 1903148572Snetchild{ 1904148572Snetchild device_set_desc_internal(dev, desc, TRUE); 1905148572Snetchild} 1906148572Snetchild 1907148572Snetchild/** 1908148572Snetchild * @brief Set the device's flags 1909148572Snetchild */ 1910148572Snetchildvoid 1911148572Snetchilddevice_set_flags(device_t dev, u_int32_t flags) 1912148572Snetchild{ 1913148572Snetchild dev->devflags = flags; 1914148572Snetchild} 1915148572Snetchild 1916148572Snetchild/** 1917148572Snetchild * @brief Return the device's softc field 1918148572Snetchild * 1919148572Snetchild * The softc is allocated and zeroed when a driver is attached, based 1920148572Snetchild * on the size field of the driver. 1921148572Snetchild */ 1922148572Snetchildvoid * 1923148572Snetchilddevice_get_softc(device_t dev) 1924148572Snetchild{ 1925148572Snetchild return (dev->softc); 1926149105Simp} 1927149105Simp 1928149105Simp/** 1929149105Simp * @brief Set the device's softc field 1930149105Simp * 1931149105Simp * Most drivers do not need to use this since the softc is allocated 1932149105Simp * automatically when the driver is attached. 1933149105Simp */ 1934148572Snetchildvoid 1935148572Snetchilddevice_set_softc(device_t dev, void *softc) 1936160165Savatar{ 1937160165Savatar if (dev->softc && !(dev->flags & DF_EXTERNALSOFTC)) 1938148330Snetchild free(dev->softc, M_BUS_SC); 1939148330Snetchild dev->softc = softc; 1940148330Snetchild if (dev->softc) 1941149105Simp dev->flags |= DF_EXTERNALSOFTC; 1942149105Simp else 1943188941Sraj dev->flags &= ~DF_EXTERNALSOFTC; 1944149105Simp} 1945163831Sjmg 1946149105Simp/** 1947149105Simp * @brief Get the device's ivars field 1948149105Simp * 1949149105Simp * The ivars field is used by the parent device to store per-device 1950149105Simp * state (e.g. the physical location of the device or a list of 1951149105Simp * resources). 1952149105Simp */ 1953149105Simpvoid * 1954149105Simpdevice_get_ivars(device_t dev) 1955149105Simp{ 1956149105Simp 1957149105Simp KASSERT(dev != NULL, ("device_get_ivars(NULL, ...)")); 1958149105Simp return (dev->ivars); 1959149105Simp} 1960149105Simp 1961149105Simp/** 1962149105Simp * @brief Set the device's ivars field 1963149105Simp */ 1964149105Simpvoid 1965149105Simpdevice_set_ivars(device_t dev, void * ivars) 1966149105Simp{ 1967149105Simp 1968160165Savatar KASSERT(dev != NULL, ("device_set_ivars(NULL, ...)")); 1969160165Savatar dev->ivars = ivars; 1970160165Savatar} 1971148330Snetchild 1972148330Snetchild/** 1973148330Snetchild * @brief Return the device's state 1974148330Snetchild */ 1975148330Snetchilddevice_state_t 1976149105Simpdevice_get_state(device_t dev) 1977149105Simp{ 1978149105Simp return (dev->state); 1979149105Simp} 1980149105Simp 1981148330Snetchild/** 1982149105Simp * @brief Set the DF_ENABLED flag for the device 1983149105Simp */ 1984149105Simpvoid 1985149105Simpdevice_enable(device_t dev) 1986149105Simp{ 1987149105Simp dev->flags |= DF_ENABLED; 1988149105Simp} 1989149105Simp 1990149105Simp/** 1991149105Simp * @brief Clear the DF_ENABLED flag for the device 1992149105Simp */ 1993149105Simpvoid 1994149105Simpdevice_disable(device_t dev) 1995164971Savatar{ 1996164971Savatar dev->flags &= ~DF_ENABLED; 1997164971Savatar} 1998164971Savatar 1999164971Savatar/** 2000164971Savatar * @brief Increment the busy counter for the device 2001164971Savatar */ 2002164971Savatarvoid 2003164971Savatardevice_busy(device_t dev) 2004164971Savatar{ 2005164971Savatar if (dev->state < DS_ATTACHED) 2006164971Savatar panic("device_busy: called for unattached device"); 2007164971Savatar if (dev->busy == 0 && dev->parent) 2008164971Savatar device_busy(dev->parent); 2009164971Savatar dev->busy++; 2010164971Savatar dev->state = DS_BUSY; 2011164971Savatar} 2012164971Savatar 2013164971Savatar/** 2014164971Savatar * @brief Decrement the busy counter for the device 2015164971Savatar */ 2016164971Savatarvoid 2017164971Savatardevice_unbusy(device_t dev) 2018164971Savatar{ 2019164971Savatar if (dev->state != DS_BUSY) 2020160165Savatar panic("device_unbusy: called for non-busy device %s", 2021160165Savatar device_get_nameunit(dev)); 2022160165Savatar dev->busy--; 2023148330Snetchild if (dev->busy == 0) { 2024148330Snetchild if (dev->parent) 2025148330Snetchild device_unbusy(dev->parent); 2026148330Snetchild dev->state = DS_ATTACHED; 2027149105Simp } 2028149105Simp} 2029149105Simp 2030164302Smatteo/** 2031164302Smatteo * @brief Set the DF_QUIET flag for the device 2032148330Snetchild */ 2033148330Snetchildvoid 2034148330Snetchilddevice_quiet(device_t dev) 2035148330Snetchild{ 2036148330Snetchild dev->flags |= DF_QUIET; 2037148330Snetchild} 2038148330Snetchild 2039148330Snetchild/** 2040148330Snetchild * @brief Clear the DF_QUIET flag for the device 2041148330Snetchild */ 2042148330Snetchildvoid 2043148330Snetchilddevice_verbose(device_t dev) 2044148330Snetchild{ 2045148330Snetchild dev->flags &= ~DF_QUIET; 2046148330Snetchild} 2047148330Snetchild 2048148543Snetchild/** 2049149113Simp * @brief Return non-zero if the DF_QUIET flag is set on the device 2050149113Simp */ 2051149113Simpint 2052149113Simpdevice_is_quiet(device_t dev) 2053149113Simp{ 2054149113Simp return ((dev->flags & DF_QUIET) != 0); 2055149113Simp} 2056149113Simp 2057149113Simp/** 2058149113Simp * @brief Return non-zero if the DF_ENABLED flag is set on the device 2059149113Simp */ 2060148330Snetchildint 2061148330Snetchilddevice_is_enabled(device_t dev) 2062149113Simp{ 2063149113Simp return ((dev->flags & DF_ENABLED) != 0); 2064149113Simp} 2065149113Simp 2066149113Simp/** 2067149113Simp * @brief Return non-zero if the device was successfully probed 2068149113Simp */ 2069149113Simpint 2070149113Simpdevice_is_alive(device_t dev) 2071149113Simp{ 2072149113Simp return (dev->state >= DS_ALIVE); 2073149113Simp} 2074149113Simp 2075149113Simp/** 2076149113Simp * @brief Return non-zero if the device currently has a driver 2077149113Simp * attached to it 2078149113Simp */ 2079149113Simpint 2080149113Simpdevice_is_attached(device_t dev) 2081149113Simp{ 2082149113Simp return (dev->state >= DS_ATTACHED); 2083149113Simp} 2084149113Simp 2085149113Simp/** 2086149113Simp * @brief Set the devclass of a device 2087149113Simp * @see devclass_add_device(). 2088149113Simp */ 2089149113Simpint 2090149113Simpdevice_set_devclass(device_t dev, const char *classname) 2091149113Simp{ 2092149113Simp devclass_t dc; 2093149113Simp int error; 2094148330Snetchild 2095148330Snetchild if (!classname) { 2096148330Snetchild if (dev->devclass) 2097148330Snetchild devclass_delete_device(dev->devclass, dev); 2098148330Snetchild return (0); 2099148330Snetchild } 2100148330Snetchild 2101151378Snetchild if (dev->devclass) { 2102151378Snetchild printf("device_set_devclass: device class already set\n"); 2103151378Snetchild return (EINVAL); 2104151378Snetchild } 2105151378Snetchild 2106151378Snetchild dc = devclass_find_internal(classname, 0, TRUE); 2107151378Snetchild if (!dc) 2108151378Snetchild return (ENOMEM); 2109151378Snetchild 2110151378Snetchild error = devclass_add_device(dc, dev); 2111161201Snetchild 2112151378Snetchild bus_data_generation_update(); 2113151378Snetchild return (error); 2114151378Snetchild} 2115151378Snetchild 2116151378Snetchild/** 2117151378Snetchild * @brief Set the driver of a device 2118151378Snetchild * 2119151378Snetchild * @retval 0 success 2120151378Snetchild * @retval EBUSY the device already has a driver attached 2121151378Snetchild * @retval ENOMEM a memory allocation failure occurred 2122151378Snetchild */ 2123151378Snetchildint 2124151378Snetchilddevice_set_driver(device_t dev, driver_t *driver) 2125151378Snetchild{ 2126151378Snetchild if (dev->state >= DS_ATTACHED) 2127151378Snetchild return (EBUSY); 2128151378Snetchild 2129151378Snetchild if (dev->driver == driver) 2130151378Snetchild return (0); 2131151378Snetchild 2132151378Snetchild if (dev->softc && !(dev->flags & DF_EXTERNALSOFTC)) { 2133151378Snetchild free(dev->softc, M_BUS_SC); 2134151378Snetchild dev->softc = NULL; 2135151378Snetchild } 2136151378Snetchild kobj_delete((kobj_t) dev, 0); 2137151378Snetchild dev->driver = driver; 2138151378Snetchild if (driver) { 2139151378Snetchild kobj_init((kobj_t) dev, (kobj_class_t) driver); 2140151378Snetchild if (!(dev->flags & DF_EXTERNALSOFTC) && driver->size > 0) { 2141151378Snetchild dev->softc = malloc(driver->size, M_BUS_SC, 2142151378Snetchild M_NOWAIT | M_ZERO); 2143151378Snetchild if (!dev->softc) { 2144151378Snetchild kobj_delete((kobj_t) dev, 0); 2145151378Snetchild kobj_init((kobj_t) dev, &null_class); 2146151378Snetchild dev->driver = NULL; 2147151378Snetchild return (ENOMEM); 2148151378Snetchild } 2149151378Snetchild } 2150151378Snetchild } else { 2151151378Snetchild kobj_init((kobj_t) dev, &null_class); 2152151378Snetchild } 2153151378Snetchild 2154151378Snetchild bus_data_generation_update(); 2155151378Snetchild return (0); 2156151378Snetchild} 2157151378Snetchild 2158151378Snetchild/** 2159151378Snetchild * @brief Probe a device and attach a driver if possible 2160151378Snetchild * 2161151378Snetchild * This function is the core of the device autoconfiguration 2162151378Snetchild * system. Its purpose is to select a suitable driver for a device and 2163151378Snetchild * then call that driver to initialise the hardware appropriately. The 2164151378Snetchild * driver is selected by calling the DEVICE_PROBE() method of a set of 2165151378Snetchild * candidate drivers and then choosing the driver which returned the 2166151378Snetchild * best value. This driver is then attached to the device using 2167151378Snetchild * device_attach(). 2168151378Snetchild * 2169151378Snetchild * The set of suitable drivers is taken from the list of drivers in 2170151378Snetchild * the parent device's devclass. If the device was originally created 2171151378Snetchild * with a specific class name (see device_add_child()), only drivers 2172151378Snetchild * with that name are probed, otherwise all drivers in the devclass 2173151378Snetchild * are probed. If no drivers return successful probe values in the 2174151378Snetchild * parent devclass, the search continues in the parent of that 2175151378Snetchild * devclass (see devclass_get_parent()) if any. 2176151378Snetchild * 2177151378Snetchild * @param dev the device to initialise 2178151378Snetchild * 2179151378Snetchild * @retval 0 success 2180151378Snetchild * @retval ENXIO no driver was found 2181151378Snetchild * @retval ENOMEM memory allocation failure 2182151378Snetchild * @retval non-zero some other unix error code 2183151378Snetchild */ 2184151378Snetchildint 2185151378Snetchilddevice_probe_and_attach(device_t dev) 2186151378Snetchild{ 2187151378Snetchild int error; 2188151378Snetchild 2189151378Snetchild GIANT_REQUIRED; 2190151378Snetchild 2191151378Snetchild if (dev->state >= DS_ALIVE && (dev->flags & DF_REBID) == 0) 2192151378Snetchild return (0); 2193151378Snetchild 2194151378Snetchild if (!(dev->flags & DF_ENABLED)) { 2195151378Snetchild if (bootverbose && device_get_name(dev) != NULL) { 2196151378Snetchild device_print_prettyname(dev); 2197151378Snetchild printf("not probed (disabled)\n"); 2198151378Snetchild } 2199151378Snetchild return (0); 2200151378Snetchild } 2201151378Snetchild if ((error = device_probe_child(dev->parent, dev)) != 0) { 2202151378Snetchild if (!(dev->flags & DF_DONENOMATCH)) { 2203151378Snetchild BUS_PROBE_NOMATCH(dev->parent, dev); 2204151378Snetchild devnomatch(dev); 2205151378Snetchild dev->flags |= DF_DONENOMATCH; 2206151378Snetchild } 2207151378Snetchild return (error); 2208151378Snetchild } 2209151378Snetchild error = device_attach(dev); 2210151378Snetchild 2211151378Snetchild return (error); 2212151378Snetchild} 2213151378Snetchild 2214151378Snetchild/** 2215151378Snetchild * @brief Attach a device driver to a device 2216151378Snetchild * 2217151378Snetchild * This function is a wrapper around the DEVICE_ATTACH() driver 2218151378Snetchild * method. In addition to calling DEVICE_ATTACH(), it initialises the 2219151378Snetchild * device's sysctl tree, optionally prints a description of the device 2220151378Snetchild * and queues a notification event for user-based device management 2221151378Snetchild * services. 2222151378Snetchild * 2223151378Snetchild * Normally this function is only called internally from 2224151378Snetchild * device_probe_and_attach(). 2225151378Snetchild * 2226151378Snetchild * @param dev the device to initialise 2227151378Snetchild * 2228151378Snetchild * @retval 0 success 2229151378Snetchild * @retval ENXIO no driver was found 2230151378Snetchild * @retval ENOMEM memory allocation failure 2231151378Snetchild * @retval non-zero some other unix error code 2232151378Snetchild */ 2233151378Snetchildint 2234151378Snetchilddevice_attach(device_t dev) 2235151378Snetchild{ 2236151378Snetchild int error; 2237151378Snetchild 2238151378Snetchild device_sysctl_init(dev); 2239151378Snetchild if (!device_is_quiet(dev)) 2240151378Snetchild device_print_child(dev->parent, dev); 2241151378Snetchild if ((error = DEVICE_ATTACH(dev)) != 0) { 2242151378Snetchild printf("device_attach: %s%d attach returned %d\n", 2243151378Snetchild dev->driver->name, dev->unit, error); 2244151378Snetchild /* Unset the class; set in device_probe_child */ 2245151378Snetchild if (dev->devclass == 0) 2246151378Snetchild device_set_devclass(dev, 0); 2247151378Snetchild device_set_driver(dev, NULL); 2248151378Snetchild device_sysctl_fini(dev); 2249151378Snetchild dev->state = DS_NOTPRESENT; 2250151378Snetchild return (error); 2251151378Snetchild } 2252151378Snetchild dev->state = DS_ATTACHED; 2253151378Snetchild devadded(dev); 2254151378Snetchild return (0); 2255151378Snetchild} 2256151378Snetchild 2257151378Snetchild/** 2258151378Snetchild * @brief Detach a driver from a device 2259151378Snetchild * 2260151378Snetchild * This function is a wrapper around the DEVICE_DETACH() driver 2261151378Snetchild * method. If the call to DEVICE_DETACH() succeeds, it calls 2262151378Snetchild * BUS_CHILD_DETACHED() for the parent of @p dev, queues a 2263151378Snetchild * notification event for user-based device management services and 2264151378Snetchild * cleans up the device's sysctl tree. 2265151378Snetchild * 2266151378Snetchild * @param dev the device to un-initialise 2267151378Snetchild * 2268151378Snetchild * @retval 0 success 2269151378Snetchild * @retval ENXIO no driver was found 2270151378Snetchild * @retval ENOMEM memory allocation failure 2271151378Snetchild * @retval non-zero some other unix error code 2272151378Snetchild */ 2273151378Snetchildint 2274151378Snetchilddevice_detach(device_t dev) 2275151378Snetchild{ 2276151378Snetchild int error; 2277151378Snetchild 2278151378Snetchild GIANT_REQUIRED; 2279151378Snetchild 2280151378Snetchild PDEBUG(("%s", DEVICENAME(dev))); 2281151378Snetchild if (dev->state == DS_BUSY) 2282151378Snetchild return (EBUSY); 2283151378Snetchild if (dev->state != DS_ATTACHED) 2284151378Snetchild return (0); 2285151378Snetchild 2286151378Snetchild if ((error = DEVICE_DETACH(dev)) != 0) 2287151378Snetchild return (error); 2288151378Snetchild devremoved(dev); 2289151378Snetchild device_printf(dev, "detached\n"); 2290151378Snetchild if (dev->parent) 2291151378Snetchild BUS_CHILD_DETACHED(dev->parent, dev); 2292151378Snetchild 2293151378Snetchild if (!(dev->flags & DF_FIXEDCLASS)) 2294151378Snetchild devclass_delete_device(dev->devclass, dev); 2295151378Snetchild 2296151378Snetchild dev->state = DS_NOTPRESENT; 2297151378Snetchild device_set_driver(dev, NULL); 2298151378Snetchild device_set_desc(dev, NULL); 2299151378Snetchild device_sysctl_fini(dev); 2300151378Snetchild 2301151378Snetchild return (0); 2302151378Snetchild} 2303151378Snetchild 2304151378Snetchild/** 2305151378Snetchild * @brief Notify a device of system shutdown 2306151378Snetchild * 2307151378Snetchild * This function calls the DEVICE_SHUTDOWN() driver method if the 2308151378Snetchild * device currently has an attached driver. 2309151378Snetchild * 2310151378Snetchild * @returns the value returned by DEVICE_SHUTDOWN() 2311151378Snetchild */ 2312151378Snetchildint 2313151378Snetchilddevice_shutdown(device_t dev) 2314151378Snetchild{ 2315151378Snetchild if (dev->state < DS_ATTACHED) 2316151378Snetchild return (0); 2317151378Snetchild return (DEVICE_SHUTDOWN(dev)); 2318151378Snetchild} 2319151378Snetchild 2320151378Snetchild/** 2321151378Snetchild * @brief Set the unit number of a device 2322151378Snetchild * 2323151378Snetchild * This function can be used to override the unit number used for a 2324151378Snetchild * device (e.g. to wire a device to a pre-configured unit number). 2325151378Snetchild */ 2326151378Snetchildint 2327151378Snetchilddevice_set_unit(device_t dev, int unit) 2328151378Snetchild{ 2329151378Snetchild devclass_t dc; 2330151378Snetchild int err; 2331151378Snetchild 2332151378Snetchild dc = device_get_devclass(dev); 2333151378Snetchild if (unit < dc->maxunit && dc->devices[unit]) 2334151378Snetchild return (EBUSY); 2335151378Snetchild err = devclass_delete_device(dc, dev); 2336151378Snetchild if (err) 2337151378Snetchild return (err); 2338151378Snetchild dev->unit = unit; 2339151378Snetchild err = devclass_add_device(dc, dev); 2340151378Snetchild if (err) 2341151378Snetchild return (err); 2342151378Snetchild 2343151378Snetchild bus_data_generation_update(); 2344151378Snetchild return (0); 2345151378Snetchild} 2346151378Snetchild 2347151378Snetchild/*======================================*/ 2348151378Snetchild/* 2349151378Snetchild * Some useful method implementations to make life easier for bus drivers. 2350151378Snetchild */ 2351151378Snetchild 2352151378Snetchild/** 2353151378Snetchild * @brief Initialise a resource list. 2354151378Snetchild * 2355151378Snetchild * @param rl the resource list to initialise 2356151378Snetchild */ 2357151378Snetchildvoid 2358151378Snetchildresource_list_init(struct resource_list *rl) 2359151378Snetchild{ 2360151378Snetchild SLIST_INIT(rl); 2361151378Snetchild} 2362151378Snetchild 2363151378Snetchild/** 2364151378Snetchild * @brief Reclaim memory used by a resource list. 2365151378Snetchild * 2366151378Snetchild * This function frees the memory for all resource entries on the list 2367151378Snetchild * (if any). 2368151378Snetchild * 2369151378Snetchild * @param rl the resource list to free 2370151378Snetchild */ 2371151378Snetchildvoid 2372151378Snetchildresource_list_free(struct resource_list *rl) 2373151378Snetchild{ 2374151378Snetchild struct resource_list_entry *rle; 2375151378Snetchild 2376151378Snetchild while ((rle = SLIST_FIRST(rl)) != NULL) { 2377151378Snetchild if (rle->res) 2378151378Snetchild panic("resource_list_free: resource entry is busy"); 2379151378Snetchild SLIST_REMOVE_HEAD(rl, link); 2380151378Snetchild free(rle, M_BUS); 2381151378Snetchild } 2382151378Snetchild} 2383151378Snetchild 2384151378Snetchild/** 2385151378Snetchild * @brief Add a resource entry. 2386151378Snetchild * 2387151378Snetchild * This function adds a resource entry using the given @p type, @p 2388151378Snetchild * start, @p end and @p count values. A rid value is chosen by 2389151378Snetchild * searching sequentially for the first unused rid starting at zero. 2390151378Snetchild * 2391151378Snetchild * @param rl the resource list to edit 2392151378Snetchild * @param type the resource entry type (e.g. SYS_RES_MEMORY) 2393151378Snetchild * @param start the start address of the resource 2394151378Snetchild * @param end the end address of the resource 2395151378Snetchild * @param count XXX end-start+1 2396151378Snetchild */ 2397151378Snetchildint 2398151378Snetchildresource_list_add_next(struct resource_list *rl, int type, u_long start, 2399151378Snetchild u_long end, u_long count) 2400151378Snetchild{ 2401151378Snetchild int rid; 2402151378Snetchild 2403151378Snetchild rid = 0; 2404151378Snetchild while (resource_list_find(rl, type, rid) != NULL) 2405151378Snetchild rid++; 2406151378Snetchild resource_list_add(rl, type, rid, start, end, count); 2407151378Snetchild return (rid); 2408151378Snetchild} 2409151378Snetchild 2410151378Snetchild/** 2411151378Snetchild * @brief Add or modify a resource entry. 2412151378Snetchild * 2413151378Snetchild * If an existing entry exists with the same type and rid, it will be 2414151378Snetchild * modified using the given values of @p start, @p end and @p 2415151378Snetchild * count. If no entry exists, a new one will be created using the 2416151378Snetchild * given values. 2417151378Snetchild * 2418151378Snetchild * @param rl the resource list to edit 2419151378Snetchild * @param type the resource entry type (e.g. SYS_RES_MEMORY) 2420151378Snetchild * @param rid the resource identifier 2421151378Snetchild * @param start the start address of the resource 2422151378Snetchild * @param end the end address of the resource 2423151378Snetchild * @param count XXX end-start+1 2424151378Snetchild */ 2425151378Snetchildvoid 2426151378Snetchildresource_list_add(struct resource_list *rl, int type, int rid, 2427151378Snetchild u_long start, u_long end, u_long count) 2428151378Snetchild{ 2429151378Snetchild struct resource_list_entry *rle; 2430151378Snetchild 2431151378Snetchild rle = resource_list_find(rl, type, rid); 2432151378Snetchild if (!rle) { 2433151378Snetchild rle = malloc(sizeof(struct resource_list_entry), M_BUS, 2434151378Snetchild M_NOWAIT); 2435151378Snetchild if (!rle) 2436151378Snetchild panic("resource_list_add: can't record entry"); 2437151378Snetchild SLIST_INSERT_HEAD(rl, rle, link); 2438151378Snetchild rle->type = type; 2439151378Snetchild rle->rid = rid; 2440151378Snetchild rle->res = NULL; 2441151378Snetchild } 2442151378Snetchild 2443151378Snetchild if (rle->res) 2444151378Snetchild panic("resource_list_add: resource entry is busy"); 2445151378Snetchild 2446151378Snetchild rle->start = start; 2447151378Snetchild rle->end = end; 2448151378Snetchild rle->count = count; 2449151378Snetchild} 2450151378Snetchild 2451151378Snetchild/** 2452151378Snetchild * @brief Find a resource entry by type and rid. 2453151378Snetchild * 2454151378Snetchild * @param rl the resource list to search 2455151378Snetchild * @param type the resource entry type (e.g. SYS_RES_MEMORY) 2456151378Snetchild * @param rid the resource identifier 2457151378Snetchild * 2458151378Snetchild * @returns the resource entry pointer or NULL if there is no such 2459151378Snetchild * entry. 2460151378Snetchild */ 2461151378Snetchildstruct resource_list_entry * 2462151378Snetchildresource_list_find(struct resource_list *rl, int type, int rid) 2463151378Snetchild{ 2464151378Snetchild struct resource_list_entry *rle; 2465151378Snetchild 2466151378Snetchild SLIST_FOREACH(rle, rl, link) { 2467151378Snetchild if (rle->type == type && rle->rid == rid) 2468151378Snetchild return (rle); 2469151378Snetchild } 2470151378Snetchild return (NULL); 2471151378Snetchild} 2472151378Snetchild 2473151378Snetchild/** 2474151378Snetchild * @brief Delete a resource entry. 2475151378Snetchild * 2476151378Snetchild * @param rl the resource list to edit 2477151378Snetchild * @param type the resource entry type (e.g. SYS_RES_MEMORY) 2478151378Snetchild * @param rid the resource identifier 2479151378Snetchild */ 2480151378Snetchildvoid 2481151378Snetchildresource_list_delete(struct resource_list *rl, int type, int rid) 2482151378Snetchild{ 2483151378Snetchild struct resource_list_entry *rle = resource_list_find(rl, type, rid); 2484151378Snetchild 2485151378Snetchild if (rle) { 2486151378Snetchild if (rle->res != NULL) 2487151378Snetchild panic("resource_list_delete: resource has not been released"); 2488151378Snetchild SLIST_REMOVE(rl, rle, resource_list_entry, link); 2489151378Snetchild free(rle, M_BUS); 2490151378Snetchild } 2491151378Snetchild} 2492151378Snetchild 2493151378Snetchild/** 2494151378Snetchild * @brief Helper function for implementing BUS_ALLOC_RESOURCE() 2495151378Snetchild * 2496151378Snetchild * Implement BUS_ALLOC_RESOURCE() by looking up a resource from the list 2497151378Snetchild * and passing the allocation up to the parent of @p bus. This assumes 2498151378Snetchild * that the first entry of @c device_get_ivars(child) is a struct 2499151378Snetchild * resource_list. This also handles 'passthrough' allocations where a 2500151378Snetchild * child is a remote descendant of bus by passing the allocation up to 2501151378Snetchild * the parent of bus. 2502151378Snetchild * 2503151378Snetchild * Typically, a bus driver would store a list of child resources 2504151378Snetchild * somewhere in the child device's ivars (see device_get_ivars()) and 2505151378Snetchild * its implementation of BUS_ALLOC_RESOURCE() would find that list and 2506151378Snetchild * then call resource_list_alloc() to perform the allocation. 2507151378Snetchild * 2508151378Snetchild * @param rl the resource list to allocate from 2509151378Snetchild * @param bus the parent device of @p child 2510151378Snetchild * @param child the device which is requesting an allocation 2511151378Snetchild * @param type the type of resource to allocate 2512151378Snetchild * @param rid a pointer to the resource identifier 2513151378Snetchild * @param start hint at the start of the resource range - pass 2514151378Snetchild * @c 0UL for any start address 2515151378Snetchild * @param end hint at the end of the resource range - pass 2516151378Snetchild * @c ~0UL for any end address 2517151378Snetchild * @param count hint at the size of range required - pass @c 1 2518151378Snetchild * for any size 2519151378Snetchild * @param flags any extra flags to control the resource 2520151378Snetchild * allocation - see @c RF_XXX flags in 2521151378Snetchild * <sys/rman.h> for details 2522151378Snetchild * 2523151378Snetchild * @returns the resource which was allocated or @c NULL if no 2524151378Snetchild * resource could be allocated 2525151378Snetchild */ 2526151378Snetchildstruct resource * 2527151378Snetchildresource_list_alloc(struct resource_list *rl, device_t bus, device_t child, 2528151378Snetchild int type, int *rid, u_long start, u_long end, u_long count, u_int flags) 2529151378Snetchild{ 2530151378Snetchild struct resource_list_entry *rle = 0; 2531151378Snetchild int passthrough = (device_get_parent(child) != bus); 2532151378Snetchild int isdefault = (start == 0UL && end == ~0UL); 2533151378Snetchild 2534151378Snetchild if (passthrough) { 2535151378Snetchild return (BUS_ALLOC_RESOURCE(device_get_parent(bus), child, 2536151378Snetchild type, rid, start, end, count, flags)); 2537151378Snetchild } 2538151378Snetchild 2539151378Snetchild rle = resource_list_find(rl, type, *rid); 2540151378Snetchild 2541151378Snetchild if (!rle) 2542151378Snetchild return (NULL); /* no resource of that type/rid */ 2543151378Snetchild 2544151378Snetchild if (rle->res) 2545151378Snetchild panic("resource_list_alloc: resource entry is busy"); 2546151378Snetchild 2547151378Snetchild if (isdefault) { 2548151378Snetchild start = rle->start; 2549151378Snetchild count = ulmax(count, rle->count); 2550151378Snetchild end = ulmax(rle->end, start + count - 1); 2551151378Snetchild } 2552151378Snetchild 2553151378Snetchild rle->res = BUS_ALLOC_RESOURCE(device_get_parent(bus), child, 2554151378Snetchild type, rid, start, end, count, flags); 2555151378Snetchild 2556151378Snetchild /* 2557151378Snetchild * Record the new range. 2558151378Snetchild */ 2559151378Snetchild if (rle->res) { 2560151378Snetchild rle->start = rman_get_start(rle->res); 2561151378Snetchild rle->end = rman_get_end(rle->res); 2562151378Snetchild rle->count = count; 2563151378Snetchild } 2564151378Snetchild 2565151378Snetchild return (rle->res); 2566151378Snetchild} 2567151378Snetchild 2568151378Snetchild/** 2569151378Snetchild * @brief Helper function for implementing BUS_RELEASE_RESOURCE() 2570151378Snetchild * 2571151378Snetchild * Implement BUS_RELEASE_RESOURCE() using a resource list. Normally 2572151378Snetchild * used with resource_list_alloc(). 2573151378Snetchild * 2574151378Snetchild * @param rl the resource list which was allocated from 2575151378Snetchild * @param bus the parent device of @p child 2576151378Snetchild * @param child the device which is requesting a release 2577151378Snetchild * @param type the type of resource to allocate 2578151378Snetchild * @param rid the resource identifier 2579151378Snetchild * @param res the resource to release 2580151378Snetchild * 2581151378Snetchild * @retval 0 success 2582151378Snetchild * @retval non-zero a standard unix error code indicating what 2583151378Snetchild * error condition prevented the operation 2584151378Snetchild */ 2585151378Snetchildint 2586151378Snetchildresource_list_release(struct resource_list *rl, device_t bus, device_t child, 2587151378Snetchild int type, int rid, struct resource *res) 2588151378Snetchild{ 2589151378Snetchild struct resource_list_entry *rle = 0; 2590151378Snetchild int passthrough = (device_get_parent(child) != bus); 2591151378Snetchild int error; 2592151378Snetchild 2593151378Snetchild if (passthrough) { 2594151378Snetchild return (BUS_RELEASE_RESOURCE(device_get_parent(bus), child, 2595151378Snetchild type, rid, res)); 2596151378Snetchild } 2597151378Snetchild 2598151378Snetchild rle = resource_list_find(rl, type, rid); 2599151378Snetchild 2600151378Snetchild if (!rle) 2601151378Snetchild panic("resource_list_release: can't find resource"); 2602151378Snetchild if (!rle->res) 2603151378Snetchild panic("resource_list_release: resource entry is not busy"); 2604151378Snetchild 2605151378Snetchild error = BUS_RELEASE_RESOURCE(device_get_parent(bus), child, 2606151378Snetchild type, rid, res); 2607151378Snetchild if (error) 2608151378Snetchild return (error); 2609151378Snetchild 2610151378Snetchild rle->res = NULL; 2611151378Snetchild return (0); 2612151378Snetchild} 2613151378Snetchild 2614151378Snetchild/** 2615151378Snetchild * @brief Print a description of resources in a resource list 2616151378Snetchild * 2617151378Snetchild * Print all resources of a specified type, for use in BUS_PRINT_CHILD(). 2618151378Snetchild * The name is printed if at least one resource of the given type is available. 2619151378Snetchild * The format is used to print resource start and end. 2620151378Snetchild * 2621151378Snetchild * @param rl the resource list to print 2622151378Snetchild * @param name the name of @p type, e.g. @c "memory" 2623151378Snetchild * @param type type type of resource entry to print 2624151378Snetchild * @param format printf(9) format string to print resource 2625151378Snetchild * start and end values 2626151378Snetchild * 2627151378Snetchild * @returns the number of characters printed 2628151378Snetchild */ 2629151378Snetchildint 2630151378Snetchildresource_list_print_type(struct resource_list *rl, const char *name, int type, 2631151378Snetchild const char *format) 2632151378Snetchild{ 2633151378Snetchild struct resource_list_entry *rle; 2634151378Snetchild int printed, retval; 2635151378Snetchild 2636151378Snetchild printed = 0; 2637151378Snetchild retval = 0; 2638151378Snetchild /* Yes, this is kinda cheating */ 2639151378Snetchild SLIST_FOREACH(rle, rl, link) { 2640151378Snetchild if (rle->type == type) { 2641151378Snetchild if (printed == 0) 2642151378Snetchild retval += printf(" %s ", name); 2643151378Snetchild else 2644151378Snetchild retval += printf(","); 2645151378Snetchild printed++; 2646151378Snetchild retval += printf(format, rle->start); 2647151378Snetchild if (rle->count > 1) { 2648151378Snetchild retval += printf("-"); 2649151378Snetchild retval += printf(format, rle->start + 2650151378Snetchild rle->count - 1); 2651151378Snetchild } 2652151378Snetchild } 2653151378Snetchild } 2654151378Snetchild return (retval); 2655151378Snetchild} 2656151378Snetchild 2657151378Snetchild/** 2658151378Snetchild * @brief Helper function for implementing DEVICE_PROBE() 2659151378Snetchild * 2660151378Snetchild * This function can be used to help implement the DEVICE_PROBE() for 2661151378Snetchild * a bus (i.e. a device which has other devices attached to it). It 2662151378Snetchild * calls the DEVICE_IDENTIFY() method of each driver in the device's 2663151378Snetchild * devclass. 2664151378Snetchild */ 2665151378Snetchildint 2666151378Snetchildbus_generic_probe(device_t dev) 2667151378Snetchild{ 2668151378Snetchild devclass_t dc = dev->devclass; 2669151378Snetchild driverlink_t dl; 2670151378Snetchild 2671151378Snetchild TAILQ_FOREACH(dl, &dc->drivers, link) { 2672151378Snetchild DEVICE_IDENTIFY(dl->driver, dev); 2673151378Snetchild } 2674151378Snetchild 2675151378Snetchild return (0); 2676151378Snetchild} 2677151378Snetchild 2678151378Snetchild/** 2679151378Snetchild * @brief Helper function for implementing DEVICE_ATTACH() 2680151378Snetchild * 2681151378Snetchild * This function can be used to help implement the DEVICE_ATTACH() for 2682151378Snetchild * a bus. It calls device_probe_and_attach() for each of the device's 2683151378Snetchild * children. 2684151378Snetchild */ 2685151378Snetchildint 2686151378Snetchildbus_generic_attach(device_t dev) 2687151378Snetchild{ 2688151378Snetchild device_t child; 2689151378Snetchild 2690151378Snetchild TAILQ_FOREACH(child, &dev->children, link) { 2691151378Snetchild device_probe_and_attach(child); 2692151378Snetchild } 2693151378Snetchild 2694151378Snetchild return (0); 2695151378Snetchild} 2696151378Snetchild 2697151378Snetchild/** 2698151378Snetchild * @brief Helper function for implementing DEVICE_DETACH() 2699151378Snetchild * 2700151378Snetchild * This function can be used to help implement the DEVICE_DETACH() for 2701151378Snetchild * a bus. It calls device_detach() for each of the device's 2702151378Snetchild * children. 2703151378Snetchild */ 2704151378Snetchildint 2705151378Snetchildbus_generic_detach(device_t dev) 2706151378Snetchild{ 2707151378Snetchild device_t child; 2708151378Snetchild int error; 2709151378Snetchild 2710151378Snetchild if (dev->state != DS_ATTACHED) 2711151378Snetchild return (EBUSY); 2712151378Snetchild 2713151378Snetchild TAILQ_FOREACH(child, &dev->children, link) { 2714151378Snetchild if ((error = device_detach(child)) != 0) 2715151378Snetchild return (error); 2716151378Snetchild } 2717151378Snetchild 2718151378Snetchild return (0); 2719151378Snetchild} 2720151378Snetchild 2721151378Snetchild/** 2722151378Snetchild * @brief Helper function for implementing DEVICE_SHUTDOWN() 2723151378Snetchild * 2724151378Snetchild * This function can be used to help implement the DEVICE_SHUTDOWN() 2725151378Snetchild * for a bus. It calls device_shutdown() for each of the device's 2726151378Snetchild * children. 2727151378Snetchild */ 2728151378Snetchildint 2729151378Snetchildbus_generic_shutdown(device_t dev) 2730151378Snetchild{ 2731151378Snetchild device_t child; 2732151378Snetchild 2733151378Snetchild TAILQ_FOREACH(child, &dev->children, link) { 2734151378Snetchild device_shutdown(child); 2735151378Snetchild } 2736151378Snetchild 2737151378Snetchild return (0); 2738151378Snetchild} 2739151378Snetchild 2740151378Snetchild/** 2741151378Snetchild * @brief Helper function for implementing DEVICE_SUSPEND() 2742151378Snetchild * 2743151378Snetchild * This function can be used to help implement the DEVICE_SUSPEND() 2744151378Snetchild * for a bus. It calls DEVICE_SUSPEND() for each of the device's 2745151378Snetchild * children. If any call to DEVICE_SUSPEND() fails, the suspend 2746151378Snetchild * operation is aborted and any devices which were suspended are 2747151378Snetchild * resumed immediately by calling their DEVICE_RESUME() methods. 2748151378Snetchild */ 2749151378Snetchildint 2750151378Snetchildbus_generic_suspend(device_t dev) 2751151378Snetchild{ 2752151378Snetchild int error; 2753151378Snetchild device_t child, child2; 2754151378Snetchild 2755151378Snetchild TAILQ_FOREACH(child, &dev->children, link) { 2756151378Snetchild error = DEVICE_SUSPEND(child); 2757151378Snetchild if (error) { 2758151378Snetchild for (child2 = TAILQ_FIRST(&dev->children); 2759151378Snetchild child2 && child2 != child; 2760151378Snetchild child2 = TAILQ_NEXT(child2, link)) 2761151378Snetchild DEVICE_RESUME(child2); 2762151378Snetchild return (error); 2763151378Snetchild } 2764151378Snetchild } 2765151378Snetchild return (0); 2766151378Snetchild} 2767151378Snetchild 2768151378Snetchild/** 2769151378Snetchild * @brief Helper function for implementing DEVICE_RESUME() 2770151378Snetchild * 2771151378Snetchild * This function can be used to help implement the DEVICE_RESUME() for 2772151378Snetchild * a bus. It calls DEVICE_RESUME() on each of the device's children. 2773151378Snetchild */ 2774151378Snetchildint 2775151378Snetchildbus_generic_resume(device_t dev) 2776151378Snetchild{ 2777151378Snetchild device_t child; 2778151378Snetchild 2779151378Snetchild TAILQ_FOREACH(child, &dev->children, link) { 2780151378Snetchild DEVICE_RESUME(child); 2781151378Snetchild /* if resume fails, there's nothing we can usefully do... */ 2782151378Snetchild } 2783151378Snetchild return (0); 2784151378Snetchild} 2785151378Snetchild 2786151378Snetchild/** 2787151378Snetchild * @brief Helper function for implementing BUS_PRINT_CHILD(). 2788151378Snetchild * 2789151378Snetchild * This function prints the first part of the ascii representation of 2790151378Snetchild * @p child, including its name, unit and description (if any - see 2791151378Snetchild * device_set_desc()). 2792151378Snetchild * 2793151378Snetchild * @returns the number of characters printed 2794151378Snetchild */ 2795151378Snetchildint 2796151378Snetchildbus_print_child_header(device_t dev, device_t child) 2797151378Snetchild{ 2798151378Snetchild int retval = 0; 2799151378Snetchild 2800151378Snetchild if (device_get_desc(child)) { 2801151378Snetchild retval += device_printf(child, "<%s>", device_get_desc(child)); 2802151378Snetchild } else { 2803151378Snetchild retval += printf("%s", device_get_nameunit(child)); 2804151378Snetchild } 2805151378Snetchild 2806151378Snetchild return (retval); 2807151378Snetchild} 2808151378Snetchild 2809151378Snetchild/** 2810151378Snetchild * @brief Helper function for implementing BUS_PRINT_CHILD(). 2811151378Snetchild * 2812151378Snetchild * This function prints the last part of the ascii representation of 2813151378Snetchild * @p child, which consists of the string @c " on " followed by the 2814151378Snetchild * name and unit of the @p dev. 2815151378Snetchild * 2816151378Snetchild * @returns the number of characters printed 2817151378Snetchild */ 2818151378Snetchildint 2819151378Snetchildbus_print_child_footer(device_t dev, device_t child) 2820151378Snetchild{ 2821151378Snetchild return (printf(" on %s\n", device_get_nameunit(dev))); 2822151378Snetchild} 2823151378Snetchild 2824151378Snetchild/** 2825151378Snetchild * @brief Helper function for implementing BUS_PRINT_CHILD(). 2826151378Snetchild * 2827151378Snetchild * This function simply calls bus_print_child_header() followed by 2828151378Snetchild * bus_print_child_footer(). 2829151378Snetchild * 2830151378Snetchild * @returns the number of characters printed 2831151378Snetchild */ 2832151378Snetchildint 2833151378Snetchildbus_generic_print_child(device_t dev, device_t child) 2834151378Snetchild{ 2835151378Snetchild int retval = 0; 2836151378Snetchild 2837151378Snetchild retval += bus_print_child_header(dev, child); 2838151378Snetchild retval += bus_print_child_footer(dev, child); 2839151378Snetchild 2840151378Snetchild return (retval); 2841151378Snetchild} 2842151378Snetchild 2843151378Snetchild/** 2844151378Snetchild * @brief Stub function for implementing BUS_READ_IVAR(). 2845151378Snetchild * 2846151378Snetchild * @returns ENOENT 2847151378Snetchild */ 2848151378Snetchildint 2849151378Snetchildbus_generic_read_ivar(device_t dev, device_t child, int index, 2850151378Snetchild uintptr_t * result) 2851151378Snetchild{ 2852151378Snetchild return (ENOENT); 2853151378Snetchild} 2854151378Snetchild 2855151378Snetchild/** 2856151378Snetchild * @brief Stub function for implementing BUS_WRITE_IVAR(). 2857151378Snetchild * 2858151378Snetchild * @returns ENOENT 2859151378Snetchild */ 2860151378Snetchildint 2861151378Snetchildbus_generic_write_ivar(device_t dev, device_t child, int index, 2862151378Snetchild uintptr_t value) 2863151378Snetchild{ 2864151378Snetchild return (ENOENT); 2865151378Snetchild} 2866151378Snetchild 2867151378Snetchild/** 2868151378Snetchild * @brief Stub function for implementing BUS_GET_RESOURCE_LIST(). 2869151378Snetchild * 2870151378Snetchild * @returns NULL 2871151378Snetchild */ 2872151378Snetchildstruct resource_list * 2873151378Snetchildbus_generic_get_resource_list(device_t dev, device_t child) 2874151378Snetchild{ 2875151378Snetchild return (NULL); 2876151378Snetchild} 2877151378Snetchild 2878151378Snetchild/** 2879151378Snetchild * @brief Helper function for implementing BUS_DRIVER_ADDED(). 2880151378Snetchild * 2881151378Snetchild * This implementation of BUS_DRIVER_ADDED() simply calls the driver's 2882151378Snetchild * DEVICE_IDENTIFY() method to allow it to add new children to the bus 2883151378Snetchild * and then calls device_probe_and_attach() for each unattached child. 2884151378Snetchild */ 2885151378Snetchildvoid 2886151378Snetchildbus_generic_driver_added(device_t dev, driver_t *driver) 2887151378Snetchild{ 2888151378Snetchild device_t child; 2889151378Snetchild 2890151378Snetchild DEVICE_IDENTIFY(driver, dev); 2891151378Snetchild TAILQ_FOREACH(child, &dev->children, link) { 2892151378Snetchild if (child->state == DS_NOTPRESENT || 2893151378Snetchild (child->flags & DF_REBID)) 2894151378Snetchild device_probe_and_attach(child); 2895151378Snetchild } 2896151378Snetchild} 2897151378Snetchild 2898151378Snetchild/** 2899151378Snetchild * @brief Helper function for implementing BUS_SETUP_INTR(). 2900151378Snetchild * 2901151378Snetchild * This simple implementation of BUS_SETUP_INTR() simply calls the 2902151378Snetchild * BUS_SETUP_INTR() method of the parent of @p dev. 2903151378Snetchild */ 2904151378Snetchildint 2905151378Snetchildbus_generic_setup_intr(device_t dev, device_t child, struct resource *irq, 2906151378Snetchild int flags, driver_intr_t *intr, void *arg, void **cookiep) 2907151378Snetchild{ 2908151378Snetchild /* Propagate up the bus hierarchy until someone handles it. */ 2909151378Snetchild if (dev->parent) 2910151378Snetchild return (BUS_SETUP_INTR(dev->parent, child, irq, flags, 2911151378Snetchild intr, arg, cookiep)); 2912151378Snetchild return (EINVAL); 2913151378Snetchild} 2914151378Snetchild 2915151378Snetchild/** 2916151378Snetchild * @brief Helper function for implementing BUS_TEARDOWN_INTR(). 2917151378Snetchild * 2918151378Snetchild * This simple implementation of BUS_TEARDOWN_INTR() simply calls the 2919151378Snetchild * BUS_TEARDOWN_INTR() method of the parent of @p dev. 2920151378Snetchild */ 2921151378Snetchildint 2922151378Snetchildbus_generic_teardown_intr(device_t dev, device_t child, struct resource *irq, 2923151378Snetchild void *cookie) 2924151378Snetchild{ 2925151378Snetchild /* Propagate up the bus hierarchy until someone handles it. */ 2926151378Snetchild if (dev->parent) 2927151378Snetchild return (BUS_TEARDOWN_INTR(dev->parent, child, irq, cookie)); 2928151378Snetchild return (EINVAL); 2929151378Snetchild} 2930151378Snetchild 2931151378Snetchild/** 2932151378Snetchild * @brief Helper function for implementing BUS_ALLOC_RESOURCE(). 2933151378Snetchild * 2934151378Snetchild * This simple implementation of BUS_ALLOC_RESOURCE() simply calls the 2935151378Snetchild * BUS_ALLOC_RESOURCE() method of the parent of @p dev. 2936151378Snetchild */ 2937151378Snetchildstruct resource * 2938151378Snetchildbus_generic_alloc_resource(device_t dev, device_t child, int type, int *rid, 2939151378Snetchild u_long start, u_long end, u_long count, u_int flags) 2940151378Snetchild{ 2941151378Snetchild /* Propagate up the bus hierarchy until someone handles it. */ 2942151378Snetchild if (dev->parent) 2943151378Snetchild return (BUS_ALLOC_RESOURCE(dev->parent, child, type, rid, 2944151378Snetchild start, end, count, flags)); 2945151378Snetchild return (NULL); 2946151378Snetchild} 2947151378Snetchild 2948151378Snetchild/** 2949151378Snetchild * @brief Helper function for implementing BUS_RELEASE_RESOURCE(). 2950151378Snetchild * 2951151378Snetchild * This simple implementation of BUS_RELEASE_RESOURCE() simply calls the 2952151378Snetchild * BUS_RELEASE_RESOURCE() method of the parent of @p dev. 2953151378Snetchild */ 2954151378Snetchildint 2955151378Snetchildbus_generic_release_resource(device_t dev, device_t child, int type, int rid, 2956151378Snetchild struct resource *r) 2957151378Snetchild{ 2958151378Snetchild /* Propagate up the bus hierarchy until someone handles it. */ 2959151378Snetchild if (dev->parent) 2960151378Snetchild return (BUS_RELEASE_RESOURCE(dev->parent, child, type, rid, 2961151378Snetchild r)); 2962151378Snetchild return (EINVAL); 2963151378Snetchild} 2964151378Snetchild 2965151378Snetchild/** 2966151378Snetchild * @brief Helper function for implementing BUS_ACTIVATE_RESOURCE(). 2967151378Snetchild * 2968151378Snetchild * This simple implementation of BUS_ACTIVATE_RESOURCE() simply calls the 2969151378Snetchild * BUS_ACTIVATE_RESOURCE() method of the parent of @p dev. 2970151378Snetchild */ 2971151378Snetchildint 2972151378Snetchildbus_generic_activate_resource(device_t dev, device_t child, int type, int rid, 2973151378Snetchild struct resource *r) 2974151378Snetchild{ 2975151378Snetchild /* Propagate up the bus hierarchy until someone handles it. */ 2976151378Snetchild if (dev->parent) 2977151378Snetchild return (BUS_ACTIVATE_RESOURCE(dev->parent, child, type, rid, 2978151378Snetchild r)); 2979151378Snetchild return (EINVAL); 2980151378Snetchild} 2981151378Snetchild 2982151378Snetchild/** 2983151378Snetchild * @brief Helper function for implementing BUS_DEACTIVATE_RESOURCE(). 2984151378Snetchild * 2985151378Snetchild * This simple implementation of BUS_DEACTIVATE_RESOURCE() simply calls the 2986151378Snetchild * BUS_DEACTIVATE_RESOURCE() method of the parent of @p dev. 2987151378Snetchild */ 2988151378Snetchildint 2989151378Snetchildbus_generic_deactivate_resource(device_t dev, device_t child, int type, 2990151378Snetchild int rid, struct resource *r) 2991151378Snetchild{ 2992151378Snetchild /* Propagate up the bus hierarchy until someone handles it. */ 2993151378Snetchild if (dev->parent) 2994151378Snetchild return (BUS_DEACTIVATE_RESOURCE(dev->parent, child, type, rid, 2995151378Snetchild r)); 2996151378Snetchild return (EINVAL); 2997151378Snetchild} 2998151378Snetchild 2999151378Snetchild/** 3000151378Snetchild * @brief Helper function for implementing BUS_CONFIG_INTR(). 3001151378Snetchild * 3002151378Snetchild * This simple implementation of BUS_CONFIG_INTR() simply calls the 3003151378Snetchild * BUS_CONFIG_INTR() method of the parent of @p dev. 3004151378Snetchild */ 3005151378Snetchildint 3006151378Snetchildbus_generic_config_intr(device_t dev, int irq, enum intr_trigger trig, 3007151378Snetchild enum intr_polarity pol) 3008151378Snetchild{ 3009151378Snetchild 3010151378Snetchild /* Propagate up the bus hierarchy until someone handles it. */ 3011151378Snetchild if (dev->parent) 3012151378Snetchild return (BUS_CONFIG_INTR(dev->parent, irq, trig, pol)); 3013151378Snetchild return (EINVAL); 3014151378Snetchild} 3015151378Snetchild 3016151378Snetchild/** 3017151378Snetchild * @brief Helper function for implementing BUS_GET_RESOURCE(). 3018151378Snetchild * 3019151378Snetchild * This implementation of BUS_GET_RESOURCE() uses the 3020151378Snetchild * resource_list_find() function to do most of the work. It calls 3021151378Snetchild * BUS_GET_RESOURCE_LIST() to find a suitable resource list to 3022151378Snetchild * search. 3023151378Snetchild */ 3024151378Snetchildint 3025151378Snetchildbus_generic_rl_get_resource(device_t dev, device_t child, int type, int rid, 3026151378Snetchild u_long *startp, u_long *countp) 3027151378Snetchild{ 3028151378Snetchild struct resource_list * rl = NULL; 3029151378Snetchild struct resource_list_entry * rle = NULL; 3030151378Snetchild 3031151378Snetchild rl = BUS_GET_RESOURCE_LIST(dev, child); 3032151378Snetchild if (!rl) 3033151378Snetchild return (EINVAL); 3034151378Snetchild 3035151378Snetchild rle = resource_list_find(rl, type, rid); 3036151378Snetchild if (!rle) 3037151378Snetchild return (ENOENT); 3038151378Snetchild 3039151378Snetchild if (startp) 3040151378Snetchild *startp = rle->start; 3041151378Snetchild if (countp) 3042151378Snetchild *countp = rle->count; 3043151378Snetchild 3044151378Snetchild return (0); 3045151378Snetchild} 3046151378Snetchild 3047151378Snetchild/** 3048151378Snetchild * @brief Helper function for implementing BUS_SET_RESOURCE(). 3049151378Snetchild * 3050151378Snetchild * This implementation of BUS_SET_RESOURCE() uses the 3051151378Snetchild * resource_list_add() function to do most of the work. It calls 3052151378Snetchild * BUS_GET_RESOURCE_LIST() to find a suitable resource list to 3053151378Snetchild * edit. 3054151378Snetchild */ 3055151378Snetchildint 3056151378Snetchildbus_generic_rl_set_resource(device_t dev, device_t child, int type, int rid, 3057151378Snetchild u_long start, u_long count) 3058151378Snetchild{ 3059151378Snetchild struct resource_list * rl = NULL; 3060151378Snetchild 3061151378Snetchild rl = BUS_GET_RESOURCE_LIST(dev, child); 3062151378Snetchild if (!rl) 3063151378Snetchild return (EINVAL); 3064151378Snetchild 3065151378Snetchild resource_list_add(rl, type, rid, start, (start + count - 1), count); 3066151378Snetchild 3067151378Snetchild return (0); 3068151378Snetchild} 3069151378Snetchild 3070151378Snetchild/** 3071151378Snetchild * @brief Helper function for implementing BUS_DELETE_RESOURCE(). 3072151378Snetchild * 3073151378Snetchild * This implementation of BUS_DELETE_RESOURCE() uses the 3074151378Snetchild * resource_list_delete() function to do most of the work. It calls 3075151378Snetchild * BUS_GET_RESOURCE_LIST() to find a suitable resource list to 3076151378Snetchild * edit. 3077151378Snetchild */ 3078151378Snetchildvoid 3079151378Snetchildbus_generic_rl_delete_resource(device_t dev, device_t child, int type, int rid) 3080151378Snetchild{ 3081151378Snetchild struct resource_list * rl = NULL; 3082151378Snetchild 3083151378Snetchild rl = BUS_GET_RESOURCE_LIST(dev, child); 3084151378Snetchild if (!rl) 3085151378Snetchild return; 3086151378Snetchild 3087151378Snetchild resource_list_delete(rl, type, rid); 3088151378Snetchild 3089151378Snetchild return; 3090151378Snetchild} 3091151378Snetchild 3092151378Snetchild/** 3093151378Snetchild * @brief Helper function for implementing BUS_RELEASE_RESOURCE(). 3094151378Snetchild * 3095151378Snetchild * This implementation of BUS_RELEASE_RESOURCE() uses the 3096151378Snetchild * resource_list_release() function to do most of the work. It calls 3097151378Snetchild * BUS_GET_RESOURCE_LIST() to find a suitable resource list. 3098151378Snetchild */ 3099151378Snetchildint 3100151378Snetchildbus_generic_rl_release_resource(device_t dev, device_t child, int type, 3101151378Snetchild int rid, struct resource *r) 3102151378Snetchild{ 3103151378Snetchild struct resource_list * rl = NULL; 3104151378Snetchild 3105151378Snetchild rl = BUS_GET_RESOURCE_LIST(dev, child); 3106151378Snetchild if (!rl) 3107151378Snetchild return (EINVAL); 3108151378Snetchild 3109151378Snetchild return (resource_list_release(rl, dev, child, type, rid, r)); 3110151378Snetchild} 3111151378Snetchild 3112151378Snetchild/** 3113151378Snetchild * @brief Helper function for implementing BUS_ALLOC_RESOURCE(). 3114151378Snetchild * 3115151378Snetchild * This implementation of BUS_ALLOC_RESOURCE() uses the 3116151378Snetchild * resource_list_alloc() function to do most of the work. It calls 3117151378Snetchild * BUS_GET_RESOURCE_LIST() to find a suitable resource list. 3118151378Snetchild */ 3119151378Snetchildstruct resource * 3120151378Snetchildbus_generic_rl_alloc_resource(device_t dev, device_t child, int type, 3121151378Snetchild int *rid, u_long start, u_long end, u_long count, u_int flags) 3122151378Snetchild{ 3123151378Snetchild struct resource_list * rl = NULL; 3124151378Snetchild 3125151378Snetchild rl = BUS_GET_RESOURCE_LIST(dev, child); 3126151378Snetchild if (!rl) 3127151378Snetchild return (NULL); 3128151378Snetchild 3129151378Snetchild return (resource_list_alloc(rl, dev, child, type, rid, 3130151378Snetchild start, end, count, flags)); 3131151378Snetchild} 3132151378Snetchild 3133151378Snetchild/** 3134151378Snetchild * @brief Helper function for implementing BUS_CHILD_PRESENT(). 3135151378Snetchild * 3136151378Snetchild * This simple implementation of BUS_CHILD_PRESENT() simply calls the 3137151378Snetchild * BUS_CHILD_PRESENT() method of the parent of @p dev. 3138151378Snetchild */ 3139151378Snetchildint 3140151378Snetchildbus_generic_child_present(device_t dev, device_t child) 3141151378Snetchild{ 3142151378Snetchild return (BUS_CHILD_PRESENT(device_get_parent(dev), dev)); 3143151378Snetchild} 3144151378Snetchild 3145151378Snetchild/* 3146151378Snetchild * Some convenience functions to make it easier for drivers to use the 3147151378Snetchild * resource-management functions. All these really do is hide the 3148151378Snetchild * indirection through the parent's method table, making for slightly 3149151378Snetchild * less-wordy code. In the future, it might make sense for this code 3150151378Snetchild * to maintain some sort of a list of resources allocated by each device. 3151151378Snetchild */ 3152151378Snetchild 3153151378Snetchild/** 3154151378Snetchild * @brief Wrapper function for BUS_ALLOC_RESOURCE(). 3155151378Snetchild * 3156151378Snetchild * This function simply calls the BUS_ALLOC_RESOURCE() method of the 3157151378Snetchild * parent of @p dev. 3158151378Snetchild */ 3159151378Snetchildstruct resource * 3160151378Snetchildbus_alloc_resource(device_t dev, int type, int *rid, u_long start, u_long end, 3161151378Snetchild u_long count, u_int flags) 3162151378Snetchild{ 3163151378Snetchild if (dev->parent == 0) 3164151378Snetchild return (0); 3165151378Snetchild return (BUS_ALLOC_RESOURCE(dev->parent, dev, type, rid, start, end, 3166151378Snetchild count, flags)); 3167151378Snetchild} 3168151378Snetchild 3169151378Snetchild/** 3170151378Snetchild * @brief Wrapper function for BUS_ACTIVATE_RESOURCE(). 3171151378Snetchild * 3172151378Snetchild * This function simply calls the BUS_ACTIVATE_RESOURCE() method of the 3173151378Snetchild * parent of @p dev. 3174151378Snetchild */ 3175151378Snetchildint 3176151378Snetchildbus_activate_resource(device_t dev, int type, int rid, struct resource *r) 3177151378Snetchild{ 3178151378Snetchild if (dev->parent == 0) 3179151378Snetchild return (EINVAL); 3180151378Snetchild return (BUS_ACTIVATE_RESOURCE(dev->parent, dev, type, rid, r)); 3181151378Snetchild} 3182151378Snetchild 3183151378Snetchild/** 3184151378Snetchild * @brief Wrapper function for BUS_DEACTIVATE_RESOURCE(). 3185151378Snetchild * 3186151378Snetchild * This function simply calls the BUS_DEACTIVATE_RESOURCE() method of the 3187151378Snetchild * parent of @p dev. 3188151378Snetchild */ 3189151378Snetchildint 3190151378Snetchildbus_deactivate_resource(device_t dev, int type, int rid, struct resource *r) 3191151378Snetchild{ 3192151378Snetchild if (dev->parent == 0) 3193151378Snetchild return (EINVAL); 3194151378Snetchild return (BUS_DEACTIVATE_RESOURCE(dev->parent, dev, type, rid, r)); 3195151378Snetchild} 3196151378Snetchild 3197151378Snetchild/** 3198151378Snetchild * @brief Wrapper function for BUS_RELEASE_RESOURCE(). 3199151378Snetchild * 3200151378Snetchild * This function simply calls the BUS_RELEASE_RESOURCE() method of the 3201151378Snetchild * parent of @p dev. 3202151378Snetchild */ 3203151378Snetchildint 3204151378Snetchildbus_release_resource(device_t dev, int type, int rid, struct resource *r) 3205151378Snetchild{ 3206151378Snetchild if (dev->parent == 0) 3207151378Snetchild return (EINVAL); 3208151378Snetchild return (BUS_RELEASE_RESOURCE(dev->parent, dev, type, rid, r)); 3209151378Snetchild} 3210151378Snetchild 3211151378Snetchild/** 3212151378Snetchild * @brief Wrapper function for BUS_SETUP_INTR(). 3213151378Snetchild * 3214151378Snetchild * This function simply calls the BUS_SETUP_INTR() method of the 3215151378Snetchild * parent of @p dev. 3216151378Snetchild */ 3217151378Snetchildint 3218151378Snetchildbus_setup_intr(device_t dev, struct resource *r, int flags, 3219151378Snetchild driver_intr_t handler, void *arg, void **cookiep) 3220151378Snetchild{ 3221151378Snetchild int error; 3222151378Snetchild 3223151378Snetchild if (dev->parent != 0) { 3224151378Snetchild if ((flags &~ INTR_ENTROPY) == (INTR_TYPE_NET | INTR_MPSAFE) && 3225151378Snetchild !debug_mpsafenet) 3226151378Snetchild flags &= ~INTR_MPSAFE; 3227151378Snetchild error = BUS_SETUP_INTR(dev->parent, dev, r, flags, 3228151378Snetchild handler, arg, cookiep); 3229151378Snetchild if (error == 0) { 3230151378Snetchild if (!(flags & (INTR_MPSAFE | INTR_FAST))) 3231151378Snetchild device_printf(dev, "[GIANT-LOCKED]\n"); 3232151378Snetchild if (bootverbose && (flags & INTR_MPSAFE)) 3233151378Snetchild device_printf(dev, "[MPSAFE]\n"); 3234151378Snetchild if (flags & INTR_FAST) 3235151378Snetchild device_printf(dev, "[FAST]\n"); 3236151378Snetchild } 3237151378Snetchild } else 3238151378Snetchild error = EINVAL; 3239151378Snetchild return (error); 3240151378Snetchild} 3241151378Snetchild 3242151378Snetchild/** 3243151378Snetchild * @brief Wrapper function for BUS_TEARDOWN_INTR(). 3244151378Snetchild * 3245151378Snetchild * This function simply calls the BUS_TEARDOWN_INTR() method of the 3246151378Snetchild * parent of @p dev. 3247151378Snetchild */ 3248151378Snetchildint 3249151378Snetchildbus_teardown_intr(device_t dev, struct resource *r, void *cookie) 3250151378Snetchild{ 3251151378Snetchild if (dev->parent == 0) 3252151378Snetchild return (EINVAL); 3253151378Snetchild return (BUS_TEARDOWN_INTR(dev->parent, dev, r, cookie)); 3254151378Snetchild} 3255151378Snetchild 3256151378Snetchild/** 3257151378Snetchild * @brief Wrapper function for BUS_SET_RESOURCE(). 3258151378Snetchild * 3259151378Snetchild * This function simply calls the BUS_SET_RESOURCE() method of the 3260151378Snetchild * parent of @p dev. 3261151378Snetchild */ 3262151378Snetchildint 3263151378Snetchildbus_set_resource(device_t dev, int type, int rid, 3264151378Snetchild u_long start, u_long count) 3265151378Snetchild{ 3266151378Snetchild return (BUS_SET_RESOURCE(device_get_parent(dev), dev, type, rid, 3267151378Snetchild start, count)); 3268151378Snetchild} 3269151378Snetchild 3270151378Snetchild/** 3271151378Snetchild * @brief Wrapper function for BUS_GET_RESOURCE(). 3272151378Snetchild * 3273151378Snetchild * This function simply calls the BUS_GET_RESOURCE() method of the 3274151378Snetchild * parent of @p dev. 3275151378Snetchild */ 3276151378Snetchildint 3277151378Snetchildbus_get_resource(device_t dev, int type, int rid, 3278151378Snetchild u_long *startp, u_long *countp) 3279151378Snetchild{ 3280151378Snetchild return (BUS_GET_RESOURCE(device_get_parent(dev), dev, type, rid, 3281151378Snetchild startp, countp)); 3282151378Snetchild} 3283151378Snetchild 3284151378Snetchild/** 3285151378Snetchild * @brief Wrapper function for BUS_GET_RESOURCE(). 3286151378Snetchild * 3287151378Snetchild * This function simply calls the BUS_GET_RESOURCE() method of the 3288151378Snetchild * parent of @p dev and returns the start value. 3289151378Snetchild */ 3290151378Snetchildu_long 3291151378Snetchildbus_get_resource_start(device_t dev, int type, int rid) 3292151378Snetchild{ 3293151378Snetchild u_long start, count; 3294151378Snetchild int error; 3295151378Snetchild 3296151378Snetchild error = BUS_GET_RESOURCE(device_get_parent(dev), dev, type, rid, 3297151378Snetchild &start, &count); 3298151378Snetchild if (error) 3299151378Snetchild return (0); 3300151378Snetchild return (start); 3301151378Snetchild} 3302151378Snetchild 3303151378Snetchild/** 3304151378Snetchild * @brief Wrapper function for BUS_GET_RESOURCE(). 3305151378Snetchild * 3306151378Snetchild * This function simply calls the BUS_GET_RESOURCE() method of the 3307151378Snetchild * parent of @p dev and returns the count value. 3308151378Snetchild */ 3309151378Snetchildu_long 3310151378Snetchildbus_get_resource_count(device_t dev, int type, int rid) 3311151378Snetchild{ 3312151378Snetchild u_long start, count; 3313151378Snetchild int error; 3314151378Snetchild 3315151378Snetchild error = BUS_GET_RESOURCE(device_get_parent(dev), dev, type, rid, 3316151378Snetchild &start, &count); 3317151378Snetchild if (error) 3318151378Snetchild return (0); 3319151378Snetchild return (count); 3320151378Snetchild} 3321151378Snetchild 3322151378Snetchild/** 3323151378Snetchild * @brief Wrapper function for BUS_DELETE_RESOURCE(). 3324151378Snetchild * 3325151378Snetchild * This function simply calls the BUS_DELETE_RESOURCE() method of the 3326151378Snetchild * parent of @p dev. 3327151378Snetchild */ 3328151378Snetchildvoid 3329151378Snetchildbus_delete_resource(device_t dev, int type, int rid) 3330151378Snetchild{ 3331151378Snetchild BUS_DELETE_RESOURCE(device_get_parent(dev), dev, type, rid); 3332151378Snetchild} 3333151378Snetchild 3334151378Snetchild/** 3335151378Snetchild * @brief Wrapper function for BUS_CHILD_PRESENT(). 3336151378Snetchild * 3337151378Snetchild * This function simply calls the BUS_CHILD_PRESENT() method of the 3338151378Snetchild * parent of @p dev. 3339151378Snetchild */ 3340151378Snetchildint 3341151378Snetchildbus_child_present(device_t child) 3342151378Snetchild{ 3343151378Snetchild return (BUS_CHILD_PRESENT(device_get_parent(child), child)); 3344151378Snetchild} 3345151378Snetchild 3346151378Snetchild/** 3347151378Snetchild * @brief Wrapper function for BUS_CHILD_PNPINFO_STR(). 3348151378Snetchild * 3349151378Snetchild * This function simply calls the BUS_CHILD_PNPINFO_STR() method of the 3350151378Snetchild * parent of @p dev. 3351151378Snetchild */ 3352151378Snetchildint 3353151378Snetchildbus_child_pnpinfo_str(device_t child, char *buf, size_t buflen) 3354151378Snetchild{ 3355151378Snetchild device_t parent; 3356151378Snetchild 3357151378Snetchild parent = device_get_parent(child); 3358151378Snetchild if (parent == NULL) { 3359151378Snetchild *buf = '\0'; 3360151378Snetchild return (0); 3361151378Snetchild } 3362151378Snetchild return (BUS_CHILD_PNPINFO_STR(parent, child, buf, buflen)); 3363151378Snetchild} 3364151378Snetchild 3365151378Snetchild/** 3366151378Snetchild * @brief Wrapper function for BUS_CHILD_LOCATION_STR(). 3367151378Snetchild * 3368151378Snetchild * This function simply calls the BUS_CHILD_LOCATION_STR() method of the 3369151378Snetchild * parent of @p dev. 3370151378Snetchild */ 3371151378Snetchildint 3372151378Snetchildbus_child_location_str(device_t child, char *buf, size_t buflen) 3373151378Snetchild{ 3374151378Snetchild device_t parent; 3375151378Snetchild 3376151378Snetchild parent = device_get_parent(child); 3377151378Snetchild if (parent == NULL) { 3378151378Snetchild *buf = '\0'; 3379151378Snetchild return (0); 3380151378Snetchild } 3381151378Snetchild return (BUS_CHILD_LOCATION_STR(parent, child, buf, buflen)); 3382151378Snetchild} 3383151378Snetchild 3384151378Snetchildstatic int 3385151378Snetchildroot_print_child(device_t dev, device_t child) 3386151378Snetchild{ 3387151378Snetchild int retval = 0; 3388151378Snetchild 3389151378Snetchild retval += bus_print_child_header(dev, child); 3390151378Snetchild retval += printf("\n"); 3391151378Snetchild 3392151378Snetchild return (retval); 3393151378Snetchild} 3394151378Snetchild 3395151378Snetchildstatic int 3396151378Snetchildroot_setup_intr(device_t dev, device_t child, driver_intr_t *intr, void *arg, 3397151378Snetchild void **cookiep) 3398151378Snetchild{ 3399151378Snetchild /* 3400151378Snetchild * If an interrupt mapping gets to here something bad has happened. 3401151378Snetchild */ 3402151378Snetchild panic("root_setup_intr"); 3403151378Snetchild} 3404151378Snetchild 3405151378Snetchild/* 3406151378Snetchild * If we get here, assume that the device is permanant and really is 3407151378Snetchild * present in the system. Removable bus drivers are expected to intercept 3408151378Snetchild * this call long before it gets here. We return -1 so that drivers that 3409151378Snetchild * really care can check vs -1 or some ERRNO returned higher in the food 3410151378Snetchild * chain. 3411151378Snetchild */ 3412151378Snetchildstatic int 3413151378Snetchildroot_child_present(device_t dev, device_t child) 3414151378Snetchild{ 3415151378Snetchild return (-1); 3416151378Snetchild} 3417151378Snetchild 3418151378Snetchildstatic kobj_method_t root_methods[] = { 3419151378Snetchild /* Device interface */ 3420151378Snetchild KOBJMETHOD(device_shutdown, bus_generic_shutdown), 3421151378Snetchild KOBJMETHOD(device_suspend, bus_generic_suspend), 3422151378Snetchild KOBJMETHOD(device_resume, bus_generic_resume), 3423151378Snetchild 3424151378Snetchild /* Bus interface */ 3425151378Snetchild KOBJMETHOD(bus_print_child, root_print_child), 3426151378Snetchild KOBJMETHOD(bus_read_ivar, bus_generic_read_ivar), 3427151378Snetchild KOBJMETHOD(bus_write_ivar, bus_generic_write_ivar), 3428151378Snetchild KOBJMETHOD(bus_setup_intr, root_setup_intr), 3429151378Snetchild KOBJMETHOD(bus_child_present, root_child_present), 3430151378Snetchild 3431151378Snetchild { 0, 0 } 3432151378Snetchild}; 3433151378Snetchild 3434151378Snetchildstatic driver_t root_driver = { 3435151378Snetchild "root", 3436151378Snetchild root_methods, 3437151378Snetchild 1, /* no softc */ 3438151378Snetchild}; 3439151378Snetchild 3440151378Snetchilddevice_t root_bus; 3441151378Snetchilddevclass_t root_devclass; 3442151378Snetchild 3443151378Snetchildstatic int 3444151378Snetchildroot_bus_module_handler(module_t mod, int what, void* arg) 3445151378Snetchild{ 3446151378Snetchild switch (what) { 3447151378Snetchild case MOD_LOAD: 3448151378Snetchild TAILQ_INIT(&bus_data_devices); 3449151378Snetchild kobj_class_compile((kobj_class_t) &root_driver); 3450151378Snetchild root_bus = make_device(NULL, "root", 0); 3451151378Snetchild root_bus->desc = "System root bus"; 3452151378Snetchild kobj_init((kobj_t) root_bus, (kobj_class_t) &root_driver); 3453151378Snetchild root_bus->driver = &root_driver; 3454151378Snetchild root_bus->state = DS_ATTACHED; 3455151378Snetchild root_devclass = devclass_find_internal("root", 0, FALSE); 3456151378Snetchild devinit(); 3457151378Snetchild return (0); 3458151378Snetchild 3459151378Snetchild case MOD_SHUTDOWN: 3460151378Snetchild device_shutdown(root_bus); 3461151378Snetchild return (0); 3462151378Snetchild default: 3463151378Snetchild return (EOPNOTSUPP); 3464151378Snetchild } 3465151378Snetchild 3466151378Snetchild return (0); 3467151378Snetchild} 3468151378Snetchild 3469151378Snetchildstatic moduledata_t root_bus_mod = { 3470151378Snetchild "rootbus", 3471151378Snetchild root_bus_module_handler, 3472151378Snetchild 0 3473151378Snetchild}; 3474151378SnetchildDECLARE_MODULE(rootbus, root_bus_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); 3475151378Snetchild 3476151378Snetchild/** 3477151378Snetchild * @brief Automatically configure devices 3478151378Snetchild * 3479151378Snetchild * This function begins the autoconfiguration process by calling 3480151378Snetchild * device_probe_and_attach() for each child of the @c root0 device. 3481151378Snetchild */ 3482151378Snetchildvoid 3483151378Snetchildroot_bus_configure(void) 3484151378Snetchild{ 3485151378Snetchild device_t dev; 3486151378Snetchild 3487151378Snetchild PDEBUG((".")); 3488151378Snetchild 3489151378Snetchild TAILQ_FOREACH(dev, &root_bus->children, link) { 3490151378Snetchild device_probe_and_attach(dev); 3491151378Snetchild } 3492151378Snetchild} 3493151378Snetchild 3494151378Snetchild/** 3495151378Snetchild * @brief Module handler for registering device drivers 3496151378Snetchild * 3497151378Snetchild * This module handler is used to automatically register device 3498151378Snetchild * drivers when modules are loaded. If @p what is MOD_LOAD, it calls 3499151378Snetchild * devclass_add_driver() for the driver described by the 3500151378Snetchild * driver_module_data structure pointed to by @p arg 3501151378Snetchild */ 3502151378Snetchildint 3503151378Snetchilddriver_module_handler(module_t mod, int what, void *arg) 3504151378Snetchild{ 3505151378Snetchild int error; 3506151378Snetchild struct driver_module_data *dmd; 3507151378Snetchild devclass_t bus_devclass; 3508151378Snetchild kobj_class_t driver; 3509151378Snetchild 3510151378Snetchild dmd = (struct driver_module_data *)arg; 3511151378Snetchild bus_devclass = devclass_find_internal(dmd->dmd_busname, 0, TRUE); 3512151378Snetchild error = 0; 3513151378Snetchild 3514151378Snetchild switch (what) { 3515151378Snetchild case MOD_LOAD: 3516151378Snetchild if (dmd->dmd_chainevh) 3517151378Snetchild error = dmd->dmd_chainevh(mod,what,dmd->dmd_chainarg); 3518151378Snetchild 3519151378Snetchild driver = dmd->dmd_driver; 3520151378Snetchild PDEBUG(("Loading module: driver %s on bus %s", 3521151378Snetchild DRIVERNAME(driver), dmd->dmd_busname)); 3522151378Snetchild error = devclass_add_driver(bus_devclass, driver); 3523151378Snetchild if (error) 3524151378Snetchild break; 3525151378Snetchild 3526151378Snetchild /* 3527151378Snetchild * If the driver has any base classes, make the 3528151378Snetchild * devclass inherit from the devclass of the driver's 3529151378Snetchild * first base class. This will allow the system to 3530151378Snetchild * search for drivers in both devclasses for children 3531151378Snetchild * of a device using this driver. 3532151378Snetchild */ 3533151378Snetchild if (driver->baseclasses) { 3534151378Snetchild const char *parentname; 3535151378Snetchild parentname = driver->baseclasses[0]->name; 3536151378Snetchild *dmd->dmd_devclass = 3537151378Snetchild devclass_find_internal(driver->name, 3538151378Snetchild parentname, TRUE); 3539151378Snetchild } else { 3540151378Snetchild *dmd->dmd_devclass = 3541151378Snetchild devclass_find_internal(driver->name, 0, TRUE); 3542151378Snetchild } 3543151378Snetchild break; 3544151378Snetchild 3545151378Snetchild case MOD_UNLOAD: 3546151378Snetchild PDEBUG(("Unloading module: driver %s from bus %s", 3547151378Snetchild DRIVERNAME(dmd->dmd_driver), 3548151378Snetchild dmd->dmd_busname)); 3549151378Snetchild error = devclass_delete_driver(bus_devclass, 3550151378Snetchild dmd->dmd_driver); 3551151378Snetchild 3552151378Snetchild if (!error && dmd->dmd_chainevh) 3553151378Snetchild error = dmd->dmd_chainevh(mod,what,dmd->dmd_chainarg); 3554151378Snetchild break; 3555151378Snetchild default: 3556151378Snetchild error = EOPNOTSUPP; 3557151378Snetchild break; 3558151378Snetchild } 3559151378Snetchild 3560151378Snetchild return (error); 3561151378Snetchild} 3562151378Snetchild 3563151378Snetchild#ifdef BUS_DEBUG 3564151378Snetchild 3565151378Snetchild/* the _short versions avoid iteration by not calling anything that prints 3566151378Snetchild * more than oneliners. I love oneliners. 3567151378Snetchild */ 3568151378Snetchild 3569151378Snetchildstatic void 3570151378Snetchildprint_device_short(device_t dev, int indent) 3571151378Snetchild{ 3572151378Snetchild if (!dev) 3573151378Snetchild return; 3574151378Snetchild 3575151378Snetchild indentprintf(("device %d: <%s> %sparent,%schildren,%s%s%s%s%s,%sivars,%ssoftc,busy=%d\n", 3576151378Snetchild dev->unit, dev->desc, 3577151378Snetchild (dev->parent? "":"no "), 3578151378Snetchild (TAILQ_EMPTY(&dev->children)? "no ":""), 3579151378Snetchild (dev->flags&DF_ENABLED? "enabled,":"disabled,"), 3580151378Snetchild (dev->flags&DF_FIXEDCLASS? "fixed,":""), 3581151378Snetchild (dev->flags&DF_WILDCARD? "wildcard,":""), 3582151378Snetchild (dev->flags&DF_DESCMALLOCED? "descmalloced,":""), 3583151378Snetchild (dev->flags&DF_REBID? "rebiddable,":""), 3584151378Snetchild (dev->ivars? "":"no "), 3585151378Snetchild (dev->softc? "":"no "), 3586151378Snetchild dev->busy)); 3587151378Snetchild} 3588151378Snetchild 3589151378Snetchildstatic void 3590151378Snetchildprint_device(device_t dev, int indent) 3591151378Snetchild{ 3592151378Snetchild if (!dev) 3593151378Snetchild return; 3594151378Snetchild 3595151378Snetchild print_device_short(dev, indent); 3596151378Snetchild 3597151378Snetchild indentprintf(("Parent:\n")); 3598151378Snetchild print_device_short(dev->parent, indent+1); 3599151378Snetchild indentprintf(("Driver:\n")); 3600151378Snetchild print_driver_short(dev->driver, indent+1); 3601151378Snetchild indentprintf(("Devclass:\n")); 3602151378Snetchild print_devclass_short(dev->devclass, indent+1); 3603151378Snetchild} 3604151378Snetchild 3605151378Snetchildvoid 3606151378Snetchildprint_device_tree_short(device_t dev, int indent) 3607151378Snetchild/* print the device and all its children (indented) */ 3608151378Snetchild{ 3609151378Snetchild device_t child; 3610151378Snetchild 3611151378Snetchild if (!dev) 3612151378Snetchild return; 3613151378Snetchild 3614151378Snetchild print_device_short(dev, indent); 3615151378Snetchild 3616151378Snetchild TAILQ_FOREACH(child, &dev->children, link) { 3617151378Snetchild print_device_tree_short(child, indent+1); 3618151378Snetchild } 3619151378Snetchild} 3620151378Snetchild 3621151378Snetchildvoid 3622151378Snetchildprint_device_tree(device_t dev, int indent) 3623151378Snetchild/* print the device and all its children (indented) */ 3624151378Snetchild{ 3625151378Snetchild device_t child; 3626151378Snetchild 3627151378Snetchild if (!dev) 3628151378Snetchild return; 3629151378Snetchild 3630151378Snetchild print_device(dev, indent); 3631151378Snetchild 3632151378Snetchild TAILQ_FOREACH(child, &dev->children, link) { 3633151378Snetchild print_device_tree(child, indent+1); 3634151378Snetchild } 3635151378Snetchild} 3636151378Snetchild 3637151378Snetchildstatic void 3638151378Snetchildprint_driver_short(driver_t *driver, int indent) 3639151378Snetchild{ 3640151378Snetchild if (!driver) 3641151378Snetchild return; 3642151378Snetchild 3643151378Snetchild indentprintf(("driver %s: softc size = %zd\n", 3644151378Snetchild driver->name, driver->size)); 3645151378Snetchild} 3646151378Snetchild 3647151378Snetchildstatic void 3648151378Snetchildprint_driver(driver_t *driver, int indent) 3649151378Snetchild{ 3650151378Snetchild if (!driver) 3651151378Snetchild return; 3652151378Snetchild 3653151378Snetchild print_driver_short(driver, indent); 3654151378Snetchild} 3655151378Snetchild 3656151378Snetchild 3657151378Snetchildstatic void 3658151378Snetchildprint_driver_list(driver_list_t drivers, int indent) 3659151378Snetchild{ 3660151378Snetchild driverlink_t driver; 3661151378Snetchild 3662151378Snetchild TAILQ_FOREACH(driver, &drivers, link) { 3663151378Snetchild print_driver(driver->driver, indent); 3664151378Snetchild } 3665151378Snetchild} 3666151378Snetchild 3667151378Snetchildstatic void 3668151378Snetchildprint_devclass_short(devclass_t dc, int indent) 3669151378Snetchild{ 3670151378Snetchild if ( !dc ) 3671151378Snetchild return; 3672151378Snetchild 3673151378Snetchild indentprintf(("devclass %s: max units = %d\n", dc->name, dc->maxunit)); 3674151378Snetchild} 3675151378Snetchild 3676151378Snetchildstatic void 3677151378Snetchildprint_devclass(devclass_t dc, int indent) 3678151378Snetchild{ 3679151378Snetchild int i; 3680151378Snetchild 3681151378Snetchild if ( !dc ) 3682151378Snetchild return; 3683151378Snetchild 3684151378Snetchild print_devclass_short(dc, indent); 3685151378Snetchild indentprintf(("Drivers:\n")); 3686151378Snetchild print_driver_list(dc->drivers, indent+1); 3687151378Snetchild 3688151378Snetchild indentprintf(("Devices:\n")); 3689151378Snetchild for (i = 0; i < dc->maxunit; i++) 3690151378Snetchild if (dc->devices[i]) 3691151378Snetchild print_device(dc->devices[i], indent+1); 3692151378Snetchild} 3693151378Snetchild 3694151378Snetchildvoid 3695151378Snetchildprint_devclass_list_short(void) 3696151378Snetchild{ 3697151378Snetchild devclass_t dc; 3698151378Snetchild 3699151378Snetchild printf("Short listing of devclasses, drivers & devices:\n"); 3700151378Snetchild TAILQ_FOREACH(dc, &devclasses, link) { 3701151378Snetchild print_devclass_short(dc, 0); 3702151378Snetchild } 3703151378Snetchild} 3704151378Snetchild 3705151378Snetchildvoid 3706151378Snetchildprint_devclass_list(void) 3707151378Snetchild{ 3708151378Snetchild devclass_t dc; 3709151378Snetchild 3710151378Snetchild printf("Full listing of devclasses, drivers & devices:\n"); 3711151378Snetchild TAILQ_FOREACH(dc, &devclasses, link) { 3712151378Snetchild print_devclass(dc, 0); 3713151378Snetchild } 3714151378Snetchild} 3715151378Snetchild 3716151378Snetchild#endif 3717151378Snetchild 3718151378Snetchild/* 3719151378Snetchild * User-space access to the device tree. 3720151378Snetchild * 3721151378Snetchild * We implement a small set of nodes: 3722151378Snetchild * 3723151378Snetchild * hw.bus Single integer read method to obtain the 3724151378Snetchild * current generation count. 3725151378Snetchild * hw.bus.devices Reads the entire device tree in flat space. 3726151378Snetchild * hw.bus.rman Resource manager interface 3727151378Snetchild * 3728151378Snetchild * We might like to add the ability to scan devclasses and/or drivers to 3729151378Snetchild * determine what else is currently loaded/available. 3730151378Snetchild */ 3731151378Snetchild 3732151378Snetchildstatic int 3733151378Snetchildsysctl_bus(SYSCTL_HANDLER_ARGS) 3734151378Snetchild{ 3735151378Snetchild struct u_businfo ubus; 3736151378Snetchild 3737151378Snetchild ubus.ub_version = BUS_USER_VERSION; 3738151378Snetchild ubus.ub_generation = bus_data_generation; 3739151378Snetchild 3740151378Snetchild return (SYSCTL_OUT(req, &ubus, sizeof(ubus))); 3741151378Snetchild} 3742151378SnetchildSYSCTL_NODE(_hw_bus, OID_AUTO, info, CTLFLAG_RW, sysctl_bus, 3743151378Snetchild "bus-related data"); 3744151378Snetchild 3745151378Snetchildstatic int 3746151378Snetchildsysctl_devices(SYSCTL_HANDLER_ARGS) 3747151378Snetchild{ 3748151378Snetchild int *name = (int *)arg1; 3749151378Snetchild u_int namelen = arg2; 3750151378Snetchild int index; 3751151378Snetchild struct device *dev; 3752151378Snetchild struct u_device udev; /* XXX this is a bit big */ 3753151378Snetchild int error; 3754151378Snetchild 3755151378Snetchild if (namelen != 2) 3756151378Snetchild return (EINVAL); 3757151378Snetchild 3758151378Snetchild if (bus_data_generation_check(name[0])) 3759151378Snetchild return (EINVAL); 3760151378Snetchild 3761151378Snetchild index = name[1]; 3762151378Snetchild 3763151378Snetchild /* 3764151378Snetchild * Scan the list of devices, looking for the requested index. 3765151378Snetchild */ 3766151378Snetchild TAILQ_FOREACH(dev, &bus_data_devices, devlink) { 3767151378Snetchild if (index-- == 0) 3768151378Snetchild break; 3769151378Snetchild } 3770151378Snetchild if (dev == NULL) 3771151378Snetchild return (ENOENT); 3772151378Snetchild 3773151378Snetchild /* 3774151378Snetchild * Populate the return array. 3775151378Snetchild */ 3776151378Snetchild udev.dv_handle = (uintptr_t)dev; 3777151378Snetchild udev.dv_parent = (uintptr_t)dev->parent; 3778151378Snetchild if (dev->nameunit == NULL) 3779151378Snetchild udev.dv_name[0] = '\0'; 3780151378Snetchild else 3781151378Snetchild strlcpy(udev.dv_name, dev->nameunit, sizeof(udev.dv_name)); 3782151378Snetchild 3783151378Snetchild if (dev->desc == NULL) 3784151378Snetchild udev.dv_desc[0] = '\0'; 3785151378Snetchild else 3786151378Snetchild strlcpy(udev.dv_desc, dev->desc, sizeof(udev.dv_desc)); 3787151378Snetchild if (dev->driver == NULL || dev->driver->name == NULL) 3788151378Snetchild udev.dv_drivername[0] = '\0'; 3789151378Snetchild else 3790151378Snetchild strlcpy(udev.dv_drivername, dev->driver->name, 3791151378Snetchild sizeof(udev.dv_drivername)); 3792151378Snetchild udev.dv_pnpinfo[0] = '\0'; 3793151378Snetchild udev.dv_location[0] = '\0'; 3794153939Snetchild bus_child_pnpinfo_str(dev, udev.dv_pnpinfo, sizeof(udev.dv_pnpinfo)); 3795153939Snetchild bus_child_location_str(dev, udev.dv_location, sizeof(udev.dv_location)); 3796153939Snetchild udev.dv_devflags = dev->devflags; 3797153939Snetchild udev.dv_flags = dev->flags; 3798153939Snetchild udev.dv_state = dev->state; 3799153939Snetchild error = SYSCTL_OUT(req, &udev, sizeof(udev)); 3800153939Snetchild return (error); 3801153939Snetchild} 3802153939Snetchild 3803153939SnetchildSYSCTL_NODE(_hw_bus, OID_AUTO, devices, CTLFLAG_RD, sysctl_devices, 3804153939Snetchild "system device tree"); 3805153939Snetchild 3806153939Snetchild/* 3807153939Snetchild * Sysctl interface for scanning the resource lists. 3808153939Snetchild * 3809153939Snetchild * We take two input parameters; the index into the list of resource 3810153939Snetchild * managers, and the resource offset into the list. 3811153939Snetchild */ 3812153939Snetchildstatic int 3813151378Snetchildsysctl_rman(SYSCTL_HANDLER_ARGS) 3814151378Snetchild{ 3815151378Snetchild int *name = (int *)arg1; 3816151378Snetchild u_int namelen = arg2; 3817151378Snetchild int rman_idx, res_idx; 3818151378Snetchild struct rman *rm; 3819151378Snetchild struct resource *res; 3820151378Snetchild struct u_rman urm; 3821151378Snetchild struct u_resource ures; 3822151378Snetchild int error; 3823151378Snetchild 3824151378Snetchild if (namelen != 3) 3825151378Snetchild return (EINVAL); 3826151378Snetchild 3827151378Snetchild if (bus_data_generation_check(name[0])) 3828151378Snetchild return (EINVAL); 3829151378Snetchild rman_idx = name[1]; 3830151378Snetchild res_idx = name[2]; 3831151378Snetchild 3832151378Snetchild /* 3833151378Snetchild * Find the indexed resource manager 3834151378Snetchild */ 3835151378Snetchild TAILQ_FOREACH(rm, &rman_head, rm_link) { 3836151378Snetchild if (rman_idx-- == 0) 3837151378Snetchild break; 3838151378Snetchild } 3839151378Snetchild if (rm == NULL) 3840151378Snetchild return (ENOENT); 3841151378Snetchild 3842151378Snetchild /* 3843151378Snetchild * If the resource index is -1, we want details on the 3844151378Snetchild * resource manager. 3845151378Snetchild */ 3846151378Snetchild if (res_idx == -1) { 3847151378Snetchild urm.rm_handle = (uintptr_t)rm; 3848151378Snetchild strlcpy(urm.rm_descr, rm->rm_descr, RM_TEXTLEN); 3849151378Snetchild urm.rm_start = rm->rm_start; 3850151378Snetchild urm.rm_size = rm->rm_end - rm->rm_start + 1; 3851151378Snetchild urm.rm_type = rm->rm_type; 3852151378Snetchild 3853151378Snetchild error = SYSCTL_OUT(req, &urm, sizeof(urm)); 3854151378Snetchild return (error); 3855151378Snetchild } 3856151378Snetchild 3857151378Snetchild /* 3858151378Snetchild * Find the indexed resource and return it. 3859151378Snetchild */ 3860151378Snetchild TAILQ_FOREACH(res, &rm->rm_list, r_link) { 3861151378Snetchild if (res_idx-- == 0) { 3862151378Snetchild ures.r_handle = (uintptr_t)res; 3863151378Snetchild ures.r_parent = (uintptr_t)res->r_rm; 3864151378Snetchild ures.r_device = (uintptr_t)res->r_dev; 3865151378Snetchild if (res->r_dev != NULL) { 3866151378Snetchild if (device_get_name(res->r_dev) != NULL) { 3867151378Snetchild snprintf(ures.r_devname, RM_TEXTLEN, 3868151378Snetchild "%s%d", 3869151378Snetchild device_get_name(res->r_dev), 3870151378Snetchild device_get_unit(res->r_dev)); 3871151378Snetchild } else { 3872151378Snetchild strlcpy(ures.r_devname, "nomatch", 3873151378Snetchild RM_TEXTLEN); 3874151378Snetchild } 3875151378Snetchild } else { 3876151378Snetchild ures.r_devname[0] = '\0'; 3877151378Snetchild } 3878151378Snetchild ures.r_start = res->r_start; 3879151378Snetchild ures.r_size = res->r_end - res->r_start + 1; 3880151378Snetchild ures.r_flags = res->r_flags; 3881151378Snetchild 3882153939Snetchild error = SYSCTL_OUT(req, &ures, sizeof(ures)); 3883153939Snetchild return (error); 3884153939Snetchild } 3885153939Snetchild } 3886153939Snetchild return (ENOENT); 3887153939Snetchild} 3888153939Snetchild 3889153939SnetchildSYSCTL_NODE(_hw_bus, OID_AUTO, rman, CTLFLAG_RD, sysctl_rman, 3890153939Snetchild "kernel resource manager"); 3891153939Snetchild 3892153939Snetchildint 3893153939Snetchildbus_data_generation_check(int generation) 3894153939Snetchild{ 3895153939Snetchild if (generation != bus_data_generation) 3896153939Snetchild return (1); 3897153939Snetchild 3898153939Snetchild /* XXX generate optimised lists here? */ 3899153939Snetchild return (0); 3900153939Snetchild} 3901153939Snetchild 3902153939Snetchildvoid 3903153939Snetchildbus_data_generation_update(void) 3904153939Snetchild{ 3905153939Snetchild bus_data_generation++; 3906153939Snetchild} 3907153939Snetchild