PERFORCE change 130355 for review
Maxim Zhuravlev
thioretic at FreeBSD.org
Thu Dec 6 10:15:29 PST 2007
http://perforce.freebsd.org/chv.cgi?CH=130355
Change 130355 by thioretic at thioretic on 2007/12/06 18:14:38
Drivers should be able to specify whether newbus to enqueue incoming io requests
for possible additional processing (like prioritization) for devices
controlled by the driver.
Affected files ...
.. //depot/projects/soc2007/thioretic_gidl2/kern/subr_bus.c#9 edit
.. //depot/projects/soc2007/thioretic_gidl2/kern/subr_busio.c#6 edit
Differences ...
==== //depot/projects/soc2007/thioretic_gidl2/kern/subr_bus.c#9 (text+ko) ====
@@ -1,5250 +1,5251 @@
-/*-
- * 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 <sys/cdefs.h>
-__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 <sys/param.h>
-#include <sys/conf.h>
-#include <sys/filio.h>
-#include <sys/lock.h>
-#include <sys/kernel.h>
-#include <sys/kobj.h>
-#include <sys/malloc.h>
-#include <sys/module.h>
-#include <sys/mutex.h>
-#include <sys/poll.h>
-#include <sys/proc.h>
-#include <sys/condvar.h>
-#include <sys/queue.h>
-#include <machine/bus.h>
-#include <sys/rman.h>
-#include <sys/selinfo.h>
-#include <sys/signalvar.h>
-#include <sys/sysctl.h>
-#include <sys/systm.h>
-#include <sys/uio.h>
-#include <sys/bus.h>
-
-#include <machine/stdarg.h>
-
-#include <vm/uma.h>
-
-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;
+/*-
+ * 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 <sys/cdefs.h>
+__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 <sys/param.h>
+#include <sys/conf.h>
+#include <sys/filio.h>
+#include <sys/lock.h>
+#include <sys/kernel.h>
+#include <sys/kobj.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/poll.h>
+#include <sys/proc.h>
+#include <sys/condvar.h>
+#include <sys/queue.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <sys/selinfo.h>
+#include <sys/signalvar.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
+#include <sys/uio.h>
+#include <sys/bus.h>
+
+#include <machine/stdarg.h>
+
+#include <vm/uma.h>
+
+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;
#define DC_ATTACHCHILDDEV (1<<0)
- uint32_t flags;
-};
-
-/**
- * @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; iJ<indent; iJ++) printf(" "); printf p ; } while (0)
-
-static void print_device_short(device_t dev, int indent);
-static void print_device(device_t dev, int indent);
-void print_device_tree_short(device_t dev, int indent);
-void print_device_tree(device_t dev, int indent);
-static void print_driver_short(driver_t *driver, int indent);
-static void print_driver(driver_t *driver, int indent);
-static void print_driver_list(driver_list_t drivers, int indent);
-static void print_devclass_short(devclass_t dc, int indent);
-static void print_devclass(devclass_t dc, int indent);
-void print_devclass_list_short(void);
-void print_devclass_list(void);
-
-#else
-/* Make the compiler ignore the function calls */
-#define PDEBUG(a) /* nop */
-#define DEVICENAME(d) /* nop */
-#define DRIVERNAME(d) /* nop */
-#define DEVCLANAME(d) /* nop */
-
-#define print_device_short(d,i) /* nop */
-#define print_device(d,i) /* nop */
-#define print_device_tree_short(d,i) /* nop */
-#define print_device_tree(d,i) /* nop */
-#define print_driver_short(d,i) /* nop */
-#define print_driver(d,i) /* nop */
-#define print_driver_list(d,i) /* nop */
-#define print_devclass_short(d,i) /* nop */
-#define print_devclass(d,i) /* nop */
-#define print_devclass_list_short() /* nop */
-#define print_devclass_list() /* nop */
-#endif
-
-/*
- * dev sysctl tree
- */
-
-enum {
- DEVCLASS_SYSCTL_PARENT,
-};
-
-static int
-devclass_sysctl_handler(SYSCTL_HANDLER_ARGS)
-{
- devclass_t dc = (devclass_t)arg1;
- const char *value;
-
- switch (arg2) {
- case DEVCLASS_SYSCTL_PARENT:
- value = dc->parent ? 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){
>>> TRUNCATED FOR MAIL (1000 lines) <<<
More information about the p4-projects
mailing list