From owner-p4-projects@FreeBSD.ORG Tue Aug 21 13:05:00 2007 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 977FB16A46B; Tue, 21 Aug 2007 13:05:00 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 6CEB016A468 for ; Tue, 21 Aug 2007 13:05:00 +0000 (UTC) (envelope-from thioretic@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 5961E13C465 for ; Tue, 21 Aug 2007 13:05:00 +0000 (UTC) (envelope-from thioretic@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.1/8.14.1) with ESMTP id l7LD50qi014903 for ; Tue, 21 Aug 2007 13:05:00 GMT (envelope-from thioretic@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.1/8.14.1/Submit) id l7LD4xZt014900 for perforce@freebsd.org; Tue, 21 Aug 2007 13:04:59 GMT (envelope-from thioretic@FreeBSD.org) Date: Tue, 21 Aug 2007 13:04:59 GMT Message-Id: <200708211304.l7LD4xZt014900@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to thioretic@FreeBSD.org using -f From: Maxim Zhuravlev To: Perforce Change Reviews Cc: Subject: PERFORCE change 125496 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 21 Aug 2007 13:05:01 -0000 http://perforce.freebsd.org/chv.cgi?CH=125496 Change 125496 by thioretic@thioretic_freebox on 2007/08/21 13:04:18 Just add "\n" to the file :) Affected files ... .. //depot/projects/soc2007/thioretic_gidl2/kern/subr_bus.c#6 edit Differences ... ==== //depot/projects/soc2007/thioretic_gidl2/kern/subr_bus.c#6 (text+ko) ==== @@ -1,5334 +1,5334 @@ -/*- - * Copyright (c) 1997,1998,2003 Doug Rabson - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD: src/sys/kern/subr_bus.c,v 1.184.2.5 2006/12/28 22:13:26 jhb Exp $"); - -#include "opt_bus.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -SYSCTL_NODE(_hw, OID_AUTO, bus, CTLFLAG_RW, NULL, NULL); -SYSCTL_NODE(, OID_AUTO, dev, CTLFLAG_RW, NULL, NULL); - -/* - * Used to attach drivers to devclasses. - */ -typedef struct driverlink *driverlink_t; -struct driverlink { - kobj_class_t driver; - TAILQ_ENTRY(driverlink) link; /* list of drivers in devclass */ -}; - -typedef struct driverinfo* driverinfo_t; -struct driverinfo { - kobj_class_t driver; /**< kobj class, implementing driver - & bus interface methods (from outer space)*/ - kobj_class_t drvops; /**< kobj class, implementing driverops - interface methods (from outer space)*/ - kobj_t topology_ops; /**< object of class implemented by driver - (deeply internal:))*/ - kobj_t functional_ops; /**< object of class implemented by driverops - (deeply internal:))*/ - uint32_t flags; /**< driver-specific flags (from outer space)*/ - TAILQ_ENTRY(driverinfo) link; -}; - -typedef struct driverinfolink* driverinfolink_t; -struct driverinfolink { - driverinfo_t pdriver; - void *ivars; - void *softc; -#define DF_EXTERNALSOFTC 1 /* softc not allocated by us */ - int flags; - device_state_t state; - TAILQ_ENTRY(driverinfolink) link; -}; - -/* - * Forward declarations - */ -typedef TAILQ_HEAD(devclass_list, devclass) devclass_list_t; -typedef TAILQ_HEAD(devclasslink_list, devclasslink) devclasslink_list_t; - -typedef TAILQ_HEAD(driver_list, driverlink) driver_list_t; - -typedef TAILQ_HEAD(device_list, device) device_list_t; -typedef TAILQ_HEAD(devicelink_list, devicelink) devicelink_list_t; - -typedef TAILQ_HEAD(driverinfo_list, driverinfo) driverinfo_list_t; -typedef TAILQ_HEAD(driverinfolink_list, driverinfolink) driverinfolink_list_t; - -typedef struct devclasslink* devclasslink_t; -struct devclasslink{ - devclass_t devclass_ptr; - TAILQ_ENTRY(devclasslink) link; -}; - -struct devclass { - TAILQ_ENTRY(devclass) link; - devclass_t parent; /* parent in devclass hierarchy */ - devclasslink_list_t filters; /* these are used to hold information, - used for non-DRL_LOWEST drivers' classes */ - driver_list_t drivers; /* bus devclasses store drivers for bus */ - char *name; - device_t *devices; /* array of devices indexed by unit */ - int maxunit; /* size of devices array */ - - struct sysctl_ctx_list sysctl_ctx; - struct sysctl_oid *sysctl_tree; -}; - -/** - * @brief Implementation of device. - */ -struct device { - /* - * A device is a kernel object. The first field must be the - * current ops table for the object. - */ - KOBJ_FIELDS; /**< !TRICK: will init it to drv_compat_ctrl_driver - which gonna work around stacked drivers*/ - - /* - * Device hierarchy. - */ - TAILQ_ENTRY(device) link; /**< list of devices in parent */ - TAILQ_ENTRY(device) devlink; /**< global device list membership */ - devicelink_list_t parents; - devicelink_list_t children; /**< list of child devices */ - - /* - * Details of this device. - */ - driverinfolink_t driver; /**< current driver to be probed/attached/...*/ - int driver_level; - driverinfolink_list_t drivers[DRL_LEVELS]; - int driverinfo_flags; - devclass_t devclass; /**< current device class */ - int unit; /**< current unit number */ - char* nameunit; /**< name+unit e.g. foodev0 */ - char* desc; /**< driver specific description */ - int busy; /**< count of calls to device_busy() */ - device_state_t state; /**< current device state */ - u_int32_t devflags; /**< api level flags for device_get_flags() */ - u_short flags; /**< internal device flags */ -#define DF_ENABLED 1 /* device should be probed/attached */ -#define DF_FIXEDCLASS 2 /* devclass specified at create time */ -#define DF_WILDCARD 4 /* unit was originally wildcard */ -#define DF_DESCMALLOCED 8 /* description was malloced */ -#define DF_QUIET 16 /* don't print verbose attach message */ -#define DF_DONENOMATCH 32 /* don't execute DEVICE_NOMATCH again */ -#define DF_REBID 128 /* Can rebid after attach */ -#define DF_PERSISTENT 256 /* Should not delete when refs == 0*/ - u_char order; /**< order from device_add_child_ordered() */ - u_char pad; - //void *ivars; /**< instance variables */ - //void *softc; /**< current driver's variables */ - u_long refs; - int raw; - - struct sysctl_ctx_list sysctl_ctx; /**< state for sysctl variables */ - struct sysctl_oid *sysctl_tree; /**< state for sysctl variables */ -}; - -typedef struct devicelink* devicelink_t; -struct devicelink { - device_t device_ptr; -#define DLF_ANCHOR 1 - int flags; - TAILQ(devicelink) link; -}; - -static MALLOC_DEFINE(M_BUS, "bus", "Bus data structures"); -static MALLOC_DEFINE(M_BUS_SC, "bus-sc", "Bus data structures, softc"); - -#ifdef BUS_DEBUG - -static int bus_debug = 1; -TUNABLE_INT("bus.debug", &bus_debug); -SYSCTL_INT(_debug, OID_AUTO, bus_debug, CTLFLAG_RW, &bus_debug, 0, - "Debug bus code"); - -#define PDEBUG(a) if (bus_debug) {printf("%s:%d: ", __func__, __LINE__), printf a; printf("\n");} -#define DEVICENAME(d) ((d)? device_get_name(d): "no device") -#define DRIVERNAME(d) ((d)? d->name : "no driver") -#define DEVCLANAME(d) ((d)? d->name : "no devclass") - -/** - * Produce the indenting, indent*2 spaces plus a '.' ahead of that to - * prevent syslog from deleting initial spaces - */ -#define indentprintf(p) do { int iJ; printf("."); for (iJ=0; iJparent ? dc->parent->name : ""; - break; - default: - return (EINVAL); - } - return (SYSCTL_OUT(req, value, strlen(value))); -} - -static void -devclass_sysctl_init(devclass_t dc) -{ - - if (dc->sysctl_tree != NULL) - return; - sysctl_ctx_init(&dc->sysctl_ctx); - dc->sysctl_tree = SYSCTL_ADD_NODE(&dc->sysctl_ctx, - SYSCTL_STATIC_CHILDREN(_dev), OID_AUTO, dc->name, - CTLFLAG_RD, 0, ""); - SYSCTL_ADD_PROC(&dc->sysctl_ctx, SYSCTL_CHILDREN(dc->sysctl_tree), - OID_AUTO, "%parent", CTLFLAG_RD, - dc, DEVCLASS_SYSCTL_PARENT, devclass_sysctl_handler, "A", - "parent class"); -} - -enum { - DEVICE_SYSCTL_DESC, - DEVICE_SYSCTL_DRIVER, - DEVICE_SYSCTL_LOCATION, - DEVICE_SYSCTL_PNPINFO, - DEVICE_SYSCTL_PARENT, -}; - -static int -device_sysctl_handler(SYSCTL_HANDLER_ARGS) -{ - device_t dev = (device_t)arg1; - const char *value; - char *buf; - int error; - int level; - driverinfolink_t dil; - - buf = NULL; - switch (arg2) { - case DEVICE_SYSCTL_DESC: - value = dev->desc ? dev->desc : ""; - break; - case DEVICE_SYSCTL_DRIVER: - value = buf = malloc(1024, M_BUS, M_WAITOK | M_ZERO); - buf[0]='\0'; - for (level=DRL_LOWEST; level<=DRL_TOPMOST; level++){ - switch(level){ - case DRL_LOWEST: tmpbuf="LOWEST:"; break; - case DRL_LOWER: tmpbuf="LOWER:"; break; - case DRL_MIDDLE: tmpbuf="MIDDLE:"; break; - case DRL_UPPER: tmpbuf="UPPER:"; break; - case DRL_TOPMOST: tmpbuf="TOPMOST:"; break; - } - if (strlen(tmpbuf)+strlen(buf)>1023) break; - TAILQ_FOREACH(dil, &((dev->drivers)[level]), link){ - if(strlen(dil->pdriver->driver->name)+strlen(buf)>1022) - break; - strcat(buf,dil->pdriver->driver->name); - strcat(buf,","); - } - buf[strlen(buf)]='\0'; - strcat(buf,"\n"); - } - break; - case DEVICE_SYSCTL_LOCATION: - value = buf = malloc(1024, M_BUS, M_WAITOK | M_ZERO); - bus_child_location_str(dev, buf, 1024); - break; - case DEVICE_SYSCTL_PNPINFO: - value = buf = malloc(1024, M_BUS, M_WAITOK | M_ZERO); - bus_child_pnpinfo_str(dev, buf, 1024); - break; - case DEVICE_SYSCTL_PARENT: - value = dev->parent ? dev->parent->nameunit : ""; - break; - default: - return (EINVAL); - } - error = SYSCTL_OUT(req, value, strlen(value)); - if (buf != NULL) - free(buf, M_BUS); - return (error); -} - -static void -device_sysctl_init(device_t dev) -{ - devclass_t dc = dev->devclass; - - if (dev->sysctl_tree != NULL) - return; - devclass_sysctl_init(dc); - sysctl_ctx_init(&dev->sysctl_ctx); - dev->sysctl_tree = SYSCTL_ADD_NODE(&dev->sysctl_ctx, - SYSCTL_CHILDREN(dc->sysctl_tree), OID_AUTO, - dev->nameunit + strlen(dc->name), - CTLFLAG_RD, 0, ""); - SYSCTL_ADD_PROC(&dev->sysctl_ctx, SYSCTL_CHILDREN(dev->sysctl_tree), - OID_AUTO, "%desc", CTLFLAG_RD, - dev, DEVICE_SYSCTL_DESC, device_sysctl_handler, "A", - "device description"); - SYSCTL_ADD_PROC(&dev->sysctl_ctx, SYSCTL_CHILDREN(dev->sysctl_tree), - OID_AUTO, "%driver", CTLFLAG_RD, - dev, DEVICE_SYSCTL_DRIVER, device_sysctl_handler, "A", - "device drivers names"); - SYSCTL_ADD_PROC(&dev->sysctl_ctx, SYSCTL_CHILDREN(dev->sysctl_tree), - OID_AUTO, "%location", CTLFLAG_RD, - dev, DEVICE_SYSCTL_LOCATION, device_sysctl_handler, "A", - "device location relative to parent"); - SYSCTL_ADD_PROC(&dev->sysctl_ctx, SYSCTL_CHILDREN(dev->sysctl_tree), - OID_AUTO, "%pnpinfo", CTLFLAG_RD, - dev, DEVICE_SYSCTL_PNPINFO, device_sysctl_handler, "A", - "device identification"); - SYSCTL_ADD_PROC(&dev->sysctl_ctx, SYSCTL_CHILDREN(dev->sysctl_tree), - OID_AUTO, "%parent", CTLFLAG_RD, - dev, DEVICE_SYSCTL_PARENT, device_sysctl_handler, "A", - "parent device"); -} - -static void -device_sysctl_fini(device_t dev) -{ - if (dev->sysctl_tree == NULL) - return; - sysctl_ctx_free(&dev->sysctl_ctx); - dev->sysctl_tree = NULL; -} - -/* - * /dev/devctl implementation - */ - -/* - * This design allows only one reader for /dev/devctl. This is not desirable - * in the long run, but will get a lot of hair out of this implementation. - * Maybe we should make this device a clonable device. - * - * Also note: we specifically do not attach a device to the device_t tree - * to avoid potential chicken and egg problems. One could argue that all - * of this belongs to the root node. One could also further argue that the - * sysctl interface that we have not might more properly be an ioctl - * interface, but at this stage of the game, I'm not inclined to rock that - * boat. - * - * I'm also not sure that the SIGIO support is done correctly or not, as - * I copied it from a driver that had SIGIO support that likely hasn't been - * tested since 3.4 or 2.2.8! - */ - -static int sysctl_devctl_disable(SYSCTL_HANDLER_ARGS); -static int devctl_disable = 0; -TUNABLE_INT("hw.bus.devctl_disable", &devctl_disable); -SYSCTL_PROC(_hw_bus, OID_AUTO, devctl_disable, CTLTYPE_INT | CTLFLAG_RW, 0, 0, - sysctl_devctl_disable, "I", "devctl disable"); - -static d_open_t devopen; -static d_close_t devclose; -static d_read_t devread; -static d_ioctl_t devioctl; -static d_poll_t devpoll; - -static struct cdevsw dev_cdevsw = { - .d_version = D_VERSION, - .d_flags = D_NEEDGIANT, - .d_open = devopen, - .d_close = devclose, - .d_read = devread, - .d_ioctl = devioctl, - .d_poll = devpoll, - .d_name = "devctl", -}; - -struct dev_event_info -{ - char *dei_data; - TAILQ_ENTRY(dev_event_info) dei_link; -}; - -TAILQ_HEAD(devq, dev_event_info); - -static struct dev_softc -{ - int inuse; - int nonblock; - struct mtx mtx; - struct cv cv; - struct selinfo sel; - struct devq devq; - struct proc *async_proc; -} devsoftc; - -static struct cdev *devctl_dev; - -static void -devinit(void) -{ - devctl_dev = make_dev(&dev_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, - "devctl"); - mtx_init(&devsoftc.mtx, "dev mtx", "devd", MTX_DEF); - cv_init(&devsoftc.cv, "dev cv"); - TAILQ_INIT(&devsoftc.devq); -} - -static int -devopen(struct cdev *dev, int oflags, int devtype, d_thread_t *td) -{ - if (devsoftc.inuse) - return (EBUSY); - /* move to init */ - devsoftc.inuse = 1; - devsoftc.nonblock = 0; - devsoftc.async_proc = NULL; - return (0); -} - -static int -devclose(struct cdev *dev, int fflag, int devtype, d_thread_t *td) -{ - devsoftc.inuse = 0; - mtx_lock(&devsoftc.mtx); - cv_broadcast(&devsoftc.cv); - mtx_unlock(&devsoftc.mtx); - - return (0); -} - -/* - * The read channel for this device is used to report changes to - * userland in realtime. We are required to free the data as well as - * the n1 object because we allocate them separately. Also note that - * we return one record at a time. If you try to read this device a - * character at a time, you will loose the rest of the data. Listening - * programs are expected to cope. - */ -static int -devread(struct cdev *dev, struct uio *uio, int ioflag) -{ - struct dev_event_info *n1; - int rv; - - mtx_lock(&devsoftc.mtx); - while (TAILQ_EMPTY(&devsoftc.devq)) { - if (devsoftc.nonblock) { - mtx_unlock(&devsoftc.mtx); - return (EAGAIN); - } - rv = cv_wait_sig(&devsoftc.cv, &devsoftc.mtx); - if (rv) { - /* - * Need to translate ERESTART to EINTR here? -- jake - */ - mtx_unlock(&devsoftc.mtx); - return (rv); - } - } - n1 = TAILQ_FIRST(&devsoftc.devq); - TAILQ_REMOVE(&devsoftc.devq, n1, dei_link); - mtx_unlock(&devsoftc.mtx); - rv = uiomove(n1->dei_data, strlen(n1->dei_data), uio); - free(n1->dei_data, M_BUS); - free(n1, M_BUS); - return (rv); -} - -static int -devioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, d_thread_t *td) -{ - switch (cmd) { - - case FIONBIO: - if (*(int*)data) - devsoftc.nonblock = 1; - else - devsoftc.nonblock = 0; - return (0); - case FIOASYNC: - if (*(int*)data) - devsoftc.async_proc = td->td_proc; - else - devsoftc.async_proc = NULL; - return (0); - - /* (un)Support for other fcntl() calls. */ - case FIOCLEX: - case FIONCLEX: - case FIONREAD: - case FIOSETOWN: - case FIOGETOWN: - default: - break; - } - return (ENOTTY); -} - -static int -devpoll(struct cdev *dev, int events, d_thread_t *td) -{ - int revents = 0; - - mtx_lock(&devsoftc.mtx); - if (events & (POLLIN | POLLRDNORM)) { - if (!TAILQ_EMPTY(&devsoftc.devq)) - revents = events & (POLLIN | POLLRDNORM); - else - selrecord(td, &devsoftc.sel); - } - mtx_unlock(&devsoftc.mtx); - - return (revents); -} - -/** - * @brief Queue data to be read from the devctl device - * - * Generic interface to queue data to the devctl device. It is - * assumed that @p data is properly formatted. It is further assumed - * that @p data is allocated using the M_BUS malloc type. - */ -void -devctl_queue_data(char *data) -{ - struct dev_event_info *n1 = NULL; - struct proc *p; - - n1 = malloc(sizeof(*n1), M_BUS, M_NOWAIT); - if (n1 == NULL) - return; - n1->dei_data = data; - mtx_lock(&devsoftc.mtx); - TAILQ_INSERT_TAIL(&devsoftc.devq, n1, dei_link); - cv_broadcast(&devsoftc.cv); - mtx_unlock(&devsoftc.mtx); - selwakeup(&devsoftc.sel); - p = devsoftc.async_proc; - if (p != NULL) { - PROC_LOCK(p); - psignal(p, SIGIO); - PROC_UNLOCK(p); - } -} - -/** - * @brief Send a 'notification' to userland, using standard ways - */ -void -devctl_notify(const char *system, const char *subsystem, const char *type, - const char *data) -{ - int len = 0; - char *msg; - - if (system == NULL) - return; /* BOGUS! Must specify system. */ - if (subsystem == NULL) - return; /* BOGUS! Must specify subsystem. */ - if (type == NULL) - return; /* BOGUS! Must specify type. */ - len += strlen(" system=") + strlen(system); - len += strlen(" subsystem=") + strlen(subsystem); - len += strlen(" type=") + strlen(type); - /* add in the data message plus newline. */ - if (data != NULL) - len += strlen(data); - len += 3; /* '!', '\n', and NUL */ - msg = malloc(len, M_BUS, M_NOWAIT); - if (msg == NULL) - return; /* Drop it on the floor */ - if (data != NULL) - snprintf(msg, len, "!system=%s subsystem=%s type=%s %s\n", - system, subsystem, type, data); - else - snprintf(msg, len, "!system=%s subsystem=%s type=%s\n", - system, subsystem, type); - devctl_queue_data(msg); -} - -/* - * Common routine that tries to make sending messages as easy as possible. - * We allocate memory for the data, copy strings into that, but do not - * free it unless there's an error. The dequeue part of the driver should - * free the data. We don't send data when the device is disabled. We do - * send data, even when we have no listeners, because we wish to avoid - * races relating to startup and restart of listening applications. - * - * devaddq is designed to string together the type of event, with the - * object of that event, plus the plug and play info and location info - * for that event. This is likely most useful for devices, but less - * useful for other consumers of this interface. Those should use - * the devctl_queue_data() interface instead. - */ -static void -devaddq(const char *type, const char *what, device_t dev) -{ - char *data = NULL; - char *loc = NULL; - char *pnp = NULL; - const char *parstr; - - if (devctl_disable) - return; - data = malloc(1024, M_BUS, M_NOWAIT); - if (data == NULL) - goto bad; - - /* get the bus specific location of this device */ - loc = malloc(1024, M_BUS, M_NOWAIT); - if (loc == NULL) - goto bad; - *loc = '\0'; - bus_child_location_str(dev, loc, 1024); - - /* Get the bus specific pnp info of this device */ - pnp = malloc(1024, M_BUS, M_NOWAIT); - if (pnp == NULL) - goto bad; - *pnp = '\0'; - bus_child_pnpinfo_str(dev, pnp, 1024); - - /* Get the parent of this device, or / if high enough in the tree. */ - if (device_get_parent(dev) == NULL) - parstr = "."; /* Or '/' ? */ - else - parstr = device_get_nameunit(device_get_parent(dev)); - /* String it all together. */ - snprintf(data, 1024, "%s%s at %s %s on %s\n", type, what, loc, pnp, - parstr); - free(loc, M_BUS); - free(pnp, M_BUS); - devctl_queue_data(data); - return; -bad: - free(pnp, M_BUS); - free(loc, M_BUS); - free(data, M_BUS); - return; -} - -/* - * A device was added to the tree. We are called just after it successfully - * attaches (that is, probe and attach success for this device). No call - * is made if a device is merely parented into the tree. See devnomatch - * if probe fails. If attach fails, no notification is sent (but maybe - * we should have a different message for this). - */ -static void -devadded(device_t dev) -{ - char *pnp = NULL; - char *tmp = NULL; - - pnp = malloc(1024, M_BUS, M_NOWAIT); - if (pnp == NULL) - goto fail; - tmp = malloc(1024, M_BUS, M_NOWAIT); - if (tmp == NULL) - goto fail; - *pnp = '\0'; - bus_child_pnpinfo_str(dev, pnp, 1024); - snprintf(tmp, 1024, "%s %s", device_get_nameunit(dev), pnp); - devaddq("+", tmp, dev); -fail: - if (pnp != NULL) - free(pnp, M_BUS); - if (tmp != NULL) - free(tmp, M_BUS); - return; -} - -/* - * A device was removed from the tree. We are called just before this - * happens. - */ -static void -devremoved(device_t dev) -{ - char *pnp = NULL; - char *tmp = NULL; - - pnp = malloc(1024, M_BUS, M_NOWAIT); - if (pnp == NULL) - goto fail; - tmp = malloc(1024, M_BUS, M_NOWAIT); - if (tmp == NULL) - goto fail; - *pnp = '\0'; - bus_child_pnpinfo_str(dev, pnp, 1024); - snprintf(tmp, 1024, "%s %s", device_get_nameunit(dev), pnp); - devaddq("-", tmp, dev); -fail: - if (pnp != NULL) - free(pnp, M_BUS); - if (tmp != NULL) - free(tmp, M_BUS); - return; -} - -/* - * Called when there's no match for this device. This is only called - * the first time that no match happens, so we don't keep getitng this - * message. Should that prove to be undesirable, we can change it. - * This is called when all drivers that can attach to a given bus - * decline to accept this device. Other errrors may not be detected. - */ -static void -devnomatch(device_t dev) -{ - devaddq("?", "", dev); -} - -static int -sysctl_devctl_disable(SYSCTL_HANDLER_ARGS) -{ - struct dev_event_info *n1; - int dis, error; - - dis = devctl_disable; - error = sysctl_handle_int(oidp, &dis, 0, req); - if (error || !req->newptr) - return (error); - mtx_lock(&devsoftc.mtx); - devctl_disable = dis; - if (dis) { - while (!TAILQ_EMPTY(&devsoftc.devq)) { - n1 = TAILQ_FIRST(&devsoftc.devq); - TAILQ_REMOVE(&devsoftc.devq, n1, dei_link); - free(n1->dei_data, M_BUS); - free(n1, M_BUS); - } - } - mtx_unlock(&devsoftc.mtx); - return (0); -} - -/* End of /dev/devctl code */ - -TAILQ_HEAD(,device) bus_data_devices; -static int bus_data_generation = 1; - -kobj_method_t null_methods[] = { - { 0, 0 } -}; - -DEFINE_CLASS(null, null_methods, 0); - -/* - * Driver compatibility layer implementation - */ - -static driverinfo_list_t driverinfos = TAILQ_HEAD_INITIALIZER(driverinfos); - -/** - * @internal - * - * Is used, when a driver s used in an API function, - * but is not in driverinfos. Eg. may happen, if - * device_set_driver is called by a bus with driver, set - * to kobj_class, which wasn't registered by DRIVER_MODULE(). - */ -static drv_internal_t -driverinfo_create_driver_drv_internal (driver_t *driver){ - drv_internal_t new_drv; - - new_drv = malloc (sizeof(struct drv_internal), M_TEMP, M_NOWAIT|M_ZERO); - if (new_drv){ - new_drv.devops = driver; - new_drv.flags = DR_LOWEST; - } - return (new_drv); -} -/** - * @internal - * @brief Find or add driver compatibility settings - * - * If a driver is already present in compatibility layer - * return it, else, if @p add non-zero, add it. - * - * @param driver the device class and flags - * @param add non-zero to add driver to layer - */ -static driverinfo_t -driverinfo_find_internal (drv_internal_t driver, int add) { - driverinfo_t di; - - PDEBUG(("looking for driver %s to compatibility layer", driver->devops->name)); - if (!driver) - return (NULL); - - TAILQ_FOREACH(di, &driverinfos, link){ - if (driver->devops == di->driver) - break; - } - - if (!di && add){ - PDEBUG(("adding driver %s to compatibility layer", driver->devops->name)); - di = malloc(sizeof(struct driverinfo), M_BUS, M_NOWAIT|M_ZERO); - if (!di) - return (NULL); - di->driver = driver->devops; - di->flags = driver->flags; - di->topology_ops = kobj_create (di->driver, M_BUS, M_NOWAIT|M_ZERO); - TAILQ_INSERT_TAIL(&driverinfos, di, link); - - bus_data_generation_update(); - } - return (di); -} - -/** - * @internal - * @brief find compatibility layer entry, associated - * with the driver - * - * @param driver device kobj_class pointer - */ -static driverinfo_t -driverinfo_find_driver (driver_t *driver) { - driverinfo_t di; - - TAILQ_FOREACH(di, &driverinfos, link){ - if (driver == di->driver) - break; - } - - return di; -} - -/** - * @internal - * @brief Add driver to compatibility layer - * - * If driver is already in compartibility layer - * return it, else add it - * - * @param driver devops plus flags - */ -static driverinfo_t -driverinfo_add_driver (drv_internal_t driver) { - return (driverinfo_find_internal(driver, TRUE)); +/*- + * Copyright (c) 1997,1998,2003 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD: src/sys/kern/subr_bus.c,v 1.184.2.5 2006/12/28 22:13:26 jhb Exp $"); + +#include "opt_bus.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +SYSCTL_NODE(_hw, OID_AUTO, bus, CTLFLAG_RW, NULL, NULL); +SYSCTL_NODE(, OID_AUTO, dev, CTLFLAG_RW, NULL, NULL); + +/* + * Used to attach drivers to devclasses. + */ +typedef struct driverlink *driverlink_t; +struct driverlink { + kobj_class_t driver; + TAILQ_ENTRY(driverlink) link; /* list of drivers in devclass */ +}; + +typedef struct driverinfo* driverinfo_t; +struct driverinfo { + kobj_class_t driver; /**< kobj class, implementing driver + & bus interface methods (from outer space)*/ + kobj_class_t drvops; /**< kobj class, implementing driverops + interface methods (from outer space)*/ + kobj_t topology_ops; /**< object of class implemented by driver + (deeply internal:))*/ + kobj_t functional_ops; /**< object of class implemented by driverops + (deeply internal:))*/ + uint32_t flags; /**< driver-specific flags (from outer space)*/ + TAILQ_ENTRY(driverinfo) link; +}; + +typedef struct driverinfolink* driverinfolink_t; +struct driverinfolink { + driverinfo_t pdriver; >>> TRUNCATED FOR MAIL (1000 lines) <<<