diff options
author | dfr <dfr@FreeBSD.org> | 2004-07-18 16:30:31 +0000 |
---|---|---|
committer | dfr <dfr@FreeBSD.org> | 2004-07-18 16:30:31 +0000 |
commit | 030de024cc4aad05d83788d13d57474f5760ea50 (patch) | |
tree | e796c2cccde10a96741095e8ea4d6bf061f2dce4 /sys/kern/subr_bus.c | |
parent | 7ad60316cd2a6fab33bff1ecd701c1d696895b96 (diff) | |
download | FreeBSD-src-030de024cc4aad05d83788d13d57474f5760ea50.zip FreeBSD-src-030de024cc4aad05d83788d13d57474f5760ea50.tar.gz |
Add doxygen doc comments for most of newbus and the BUS interface.
Diffstat (limited to 'sys/kern/subr_bus.c')
-rw-r--r-- | sys/kern/subr_bus.c | 965 |
1 files changed, 919 insertions, 46 deletions
diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c index ae59230..6999a77 100644 --- a/sys/kern/subr_bus.c +++ b/sys/kern/subr_bus.c @@ -87,8 +87,8 @@ struct devclass { struct sysctl_oid *sysctl_tree; }; -/* - * Implementation of device. +/** + * @brief Implementation of device. */ struct device { /* @@ -100,44 +100,37 @@ struct device { /* * Device hierarchy. */ - TAILQ_ENTRY(device) link; /* list of devices in parent */ - TAILQ_ENTRY(device) devlink; /* global device list membership */ - device_t parent; - device_list_t children; /* list of subordinate devices */ + TAILQ_ENTRY(device) link; /**< list of devices in parent */ + TAILQ_ENTRY(device) devlink; /**< global device list membership */ + device_t parent; /**< parent of this device */ + device_list_t children; /**< list of child devices */ /* * Details of this device. */ - driver_t *driver; - devclass_t devclass; /* device class which we are in */ - int unit; - char* nameunit; /* name+unit e.g. foodev0 */ - char* desc; /* driver specific description */ - int busy; /* count of calls to device_busy() */ - device_state_t state; - u_int32_t devflags; /* api level flags for device_get_flags() */ - u_short 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_EXTERNALSOFTC 64 /* softc not allocated by us */ - u_char order; /* order from device_add_child_ordered() */ + driver_t *driver; /**< current driver */ + 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_EXTERNALSOFTC 64 /* softc not allocated by us */ + u_char order; /**< order from device_add_child_ordered() */ u_char pad; - void *ivars; - void *softc; - - struct sysctl_ctx_list sysctl_ctx; - struct sysctl_oid *sysctl_tree; -}; + void *ivars; /**< instance variables */ + void *softc; /**< current driver's variables */ -struct device_op_desc { - unsigned int offset; /* offset in driver ops */ - struct method* method; /* internal method implementation */ - devop_t deflt; /* default implementation */ - const char* name; /* unique name (for registration) */ + struct sysctl_ctx_list sysctl_ctx; /**< state for sysctl variables */ + struct sysctl_oid *sysctl_tree; /**< state for sysctl variables */ }; static MALLOC_DEFINE(M_BUS, "bus", "Bus data structures"); @@ -155,7 +148,8 @@ SYSCTL_INT(_debug, OID_AUTO, bus_debug, CTLFLAG_RW, &bus_debug, 0, #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 +/** + * 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) @@ -511,10 +505,12 @@ devpoll(struct cdev *dev, int events, d_thread_t *td) 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 data is properly formatted. It is further assumed - * that data is allocated. + * 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) @@ -539,8 +535,8 @@ devctl_queue_data(char *data) } } -/* - * Send a 'notification' to userland, using standard ways +/** + * @brief Send a 'notification' to userland, using standard ways */ void devctl_notify(const char *system, const char *subsystem, const char *type, @@ -730,6 +726,22 @@ DEFINE_CLASS(null, null_methods, 0); static devclass_list_t devclasses = TAILQ_HEAD_INITIALIZER(devclasses); + +/** + * @internal + * @brief Find or create a device class + * + * If a device class with the name @p classname exists, return it, + * otherwise if @p create is non-zero create and return a new device + * class. + * + * If @p parentname is non-NULL, the parent of the devclass is set to + * the devclass of that name. + * + * @param classname the devclass name to find or create + * @param parentname the parent devclass name or @c NULL + * @param create non-zero to create a devclass + */ static devclass_t devclass_find_internal(const char *classname, const char *parentname, int create) @@ -766,18 +778,45 @@ devclass_find_internal(const char *classname, const char *parentname, return (dc); } +/** + * @brief Create a device class + * + * If a device class with the name @p classname exists, return it, + * otherwise create and return a new device class. + * + * @param classname the devclass name to find or create + */ devclass_t devclass_create(const char *classname) { return (devclass_find_internal(classname, 0, TRUE)); } +/** + * @brief Find a device class + * + * If a device class with the name @p classname exists, return it, + * otherwise return @c NULL. + * + * @param classname the devclass name to find + */ devclass_t devclass_find(const char *classname) { return (devclass_find_internal(classname, 0, FALSE)); } +/** + * @brief Add a device driver to a device class + * + * Add a device driver to a devclass. This is normally called + * automatically by DRIVER_MODULE(). The BUS_DRIVER_ADDED() method of + * all devices in the devclass will be called to allow them to attempt + * to re-probe any unmatched children. + * + * @param dc the devclass to edit + * @param driver the driver to register + */ int devclass_add_driver(devclass_t dc, driver_t *driver) { @@ -818,6 +857,20 @@ devclass_add_driver(devclass_t dc, driver_t *driver) return (0); } +/** + * @brief Delete a device driver from a device class + * + * Delete a device driver from a devclass. This is normally called + * automatically by DRIVER_MODULE(). + * + * If the driver is currently attached to any devices, + * devclass_delete_driver() will first attempt to detach from each + * device. If one of the detach calls fails, the driver will not be + * deleted. + * + * @param dc the devclass to edit + * @param driver the driver to unregister + */ int devclass_delete_driver(devclass_t busclass, driver_t *driver) { @@ -879,6 +932,9 @@ devclass_delete_driver(devclass_t busclass, driver_t *driver) return (0); } +/** + * @internal + */ static driverlink_t devclass_find_driver_internal(devclass_t dc, const char *classname) { @@ -895,6 +951,16 @@ devclass_find_driver_internal(devclass_t dc, const char *classname) return (NULL); } +/** + * @brief Search a devclass for a driver + * + * This function searches the devclass's list of drivers and returns + * the first driver whose name is @p classname or @c NULL if there is + * no driver of that name. + * + * @param dc the devclass to search + * @param classname the driver name to search for + */ kobj_class_t devclass_find_driver(devclass_t dc, const char *classname) { @@ -906,12 +972,24 @@ devclass_find_driver(devclass_t dc, const char *classname) return (NULL); } +/** + * @brief Return the name of the devclass + */ const char * devclass_get_name(devclass_t dc) { return (dc->name); } +/** + * @brief Find a device given a unit number + * + * @param dc the devclass to search + * @param unit the unit number to search for + * + * @returns the device with the given unit number or @c + * NULL if there is no such device + */ device_t devclass_get_device(devclass_t dc, int unit) { @@ -920,6 +998,16 @@ devclass_get_device(devclass_t dc, int unit) return (dc->devices[unit]); } +/** + * @brief Find the softc field of a device given a unit number + * + * @param dc the devclass to search + * @param unit the unit number to search for + * + * @returns the softc field of the device with the given + * unit number or @c NULL if there is no such + * device + */ void * devclass_get_softc(devclass_t dc, int unit) { @@ -932,6 +1020,22 @@ devclass_get_softc(devclass_t dc, int unit) return (device_get_softc(dev)); } +/** + * @brief Get a list of devices in the devclass + * + * An array containing a list of all the devices in the given devclass + * is allocated and returned in @p *devlistp. The number of devices + * in the array is returned in @p *devcountp. The caller should free + * the array using @c free(p, M_TEMP). + * + * @param dc the devclass to examine + * @param devlistp points at location for array pointer return + * value + * @param devcountp points at location for array size return value + * + * @retval 0 success + * @retval ENOMEM the array allocation failed + */ int devclass_get_devices(devclass_t dc, device_t **devlistp, int *devcountp) { @@ -962,12 +1066,26 @@ devclass_get_devices(devclass_t dc, device_t **devlistp, int *devcountp) return (0); } +/** + * @brief Get the maximum unit number used in a devclass + * + * @param dc the devclass to examine + */ int devclass_get_maxunit(devclass_t dc) { return (dc->maxunit); } +/** + * @brief Find a free unit number in a devclass + * + * This function searches for the first unused unit number greater + * that or equal to @p unit. + * + * @param dc the devclass to examine + * @param unit the first unit number to check + */ int devclass_find_free_unit(devclass_t dc, int unit) { @@ -978,12 +1096,26 @@ devclass_find_free_unit(devclass_t dc, int unit) return (unit); } +/** + * @brief Set the parent of a devclass + * + * The parent class is normally initialised automatically by + * DRIVER_MODULE(). + * + * @param dc the devclass to edit + * @param pdc the new parent devclass + */ void devclass_set_parent(devclass_t dc, devclass_t pdc) { dc->parent = pdc; } +/** + * @brief Get the parent of a devclass + * + * @param dc the devclass to examine + */ devclass_t devclass_get_parent(devclass_t dc) { @@ -1002,6 +1134,21 @@ devclass_get_sysctl_tree(devclass_t dc) return (dc->sysctl_tree); } +/** + * @internal + * @brief Allocate a unit number + * + * On entry, @p *unitp is the desired unit number (or @c -1 if any + * will do). The allocated unit number is returned in @p *unitp. + + * @param dc the devclass to allocate from + * @param unitp points at the location for the allocated unit + * number + * + * @retval 0 success + * @retval EEXIST the requested unit number is already allocated + * @retval ENOMEM memory allocation failure + */ static int devclass_alloc_unit(devclass_t dc, int *unitp) { @@ -1053,6 +1200,22 @@ devclass_alloc_unit(devclass_t dc, int *unitp) return (0); } +/** + * @internal + * @brief Add a device to a devclass + * + * A unit number is allocated for the device (using the device's + * preferred unit number if any) and the device is registered in the + * devclass. This allows the device to be looked up by its unit + * number, e.g. by decoding a dev_t minor number. + * + * @param dc the devclass to add to + * @param dev the device to add + * + * @retval 0 success + * @retval EEXIST the requested unit number is already allocated + * @retval ENOMEM memory allocation failure + */ static int devclass_add_device(devclass_t dc, device_t dev) { @@ -1079,6 +1242,18 @@ devclass_add_device(devclass_t dc, device_t dev) return (0); } +/** + * @internal + * @brief Delete a device from a devclass + * + * The device is removed from the devclass's device list and its unit + * number is freed. + + * @param dc the devclass to delete from + * @param dev the device to delete + * + * @retval 0 success + */ static int devclass_delete_device(devclass_t dc, device_t dev) { @@ -1099,6 +1274,18 @@ devclass_delete_device(devclass_t dc, device_t dev) return (0); } +/** + * @internal + * @brief Make a new device and add it as a child of @p parent + * + * @param parent the parent of the new device + * @param name the devclass name of the new device or @c NULL + * to leave the devclass unspecified + * @parem unit the unit number of the new device of @c -1 to + * leave the unit number unspecified + * + * @returns the new device + */ static device_t make_device(device_t parent, const char *name, int unit) { @@ -1154,6 +1341,10 @@ make_device(device_t parent, const char *name, int unit) return (dev); } +/** + * @internal + * @brief Print a description of a device. + */ static int device_print_child(device_t dev, device_t child) { @@ -1167,12 +1358,48 @@ device_print_child(device_t dev, device_t child) return (retval); } +/** + * @brief Create a new device + * + * This creates a new device and adds it as a child of an existing + * parent device. The new device will be added after the last existing + * child with order zero. + * + * @param dev the device which will be the parent of the + * new child device + * @param name devclass name for new device or @c NULL if not + * specified + * @param unit unit number for new device or @c -1 if not + * specified + * + * @returns the new device + */ device_t device_add_child(device_t dev, const char *name, int unit) { return (device_add_child_ordered(dev, 0, name, unit)); } +/** + * @brief Create a new device + * + * This creates a new device and adds it as a child of an existing + * parent device. The new device will be added after the last existing + * child with the same order. + * + * @param dev the device which will be the parent of the + * new child device + * @param order a value which is used to partially sort the + * children of @p dev - devices created using + * lower values of @p order appear first in @p + * dev's list of children + * @param name devclass name for new device or @c NULL if not + * specified + * @param unit unit number for new device or @c -1 if not + * specified + * + * @returns the new device + */ device_t device_add_child_ordered(device_t dev, int order, const char *name, int unit) { @@ -1210,6 +1437,19 @@ device_add_child_ordered(device_t dev, int order, const char *name, int unit) return (child); } +/** + * @brief Delete a device + * + * This function deletes a device along with all of its children. If + * the device currently has a driver attached to it, the device is + * detached first using device_detach(). + * + * @param dev the parent device + * @param child the device to delete + * + * @retval 0 success + * @retval non-zero a unit error code describing the error + */ int device_delete_child(device_t dev, device_t child) { @@ -1238,8 +1478,17 @@ device_delete_child(device_t dev, device_t child) return (0); } -/* - * Find only devices attached to this bus. +/** + * @brief Find a device given a unit number + * + * This is similar to devclass_get_devices() but only searches for + * devices which have @p dev as a parent. + * + * @param dev the parent device to search + * @param unit the unit number to search for + * + * @returns the device with the given unit number or @c + * NULL if there is no such device */ device_t device_find_child(device_t dev, const char *classname, int unit) @@ -1257,6 +1506,9 @@ device_find_child(device_t dev, const char *classname, int unit) return (NULL); } +/** + * @internal + */ static driverlink_t first_matching_driver(devclass_t dc, device_t dev) { @@ -1265,6 +1517,9 @@ first_matching_driver(devclass_t dc, device_t dev) return (TAILQ_FIRST(&dc->drivers)); } +/** + * @internal + */ static driverlink_t next_matching_driver(devclass_t dc, device_t dev, driverlink_t last) { @@ -1278,6 +1533,9 @@ next_matching_driver(devclass_t dc, device_t dev, driverlink_t last) return (TAILQ_NEXT(last, link)); } +/** + * @internal + */ static int device_probe_child(device_t dev, device_t child) { @@ -1367,12 +1625,31 @@ device_probe_child(device_t dev, device_t child) return (ENXIO); } +/** + * @brief Return the parent of a device + */ device_t device_get_parent(device_t dev) { return (dev->parent); } +/** + * @brief Get a list of children of a device + * + * An array containing a list of all the children of the given device + * is allocated and returned in @p *devlistp. The number of devices + * in the array is returned in @p *devcountp. The caller should free + * the array using @c free(p, M_TEMP). + * + * @param dev the device to examine + * @param devlistp points at location for array pointer return + * value + * @param devcountp points at location for array size return value + * + * @retval 0 success + * @retval ENOMEM the array allocation failed + */ int device_get_children(device_t dev, device_t **devlistp, int *devcountp) { @@ -1401,18 +1678,30 @@ device_get_children(device_t dev, device_t **devlistp, int *devcountp) return (0); } +/** + * @brief Return the current driver for the device or @c NULL if there + * is no driver currently attached + */ driver_t * device_get_driver(device_t dev) { return (dev->driver); } +/** + * @brief Return the current devclass for the device or @c NULL if + * there is none. + */ devclass_t device_get_devclass(device_t dev) { return (dev->devclass); } +/** + * @brief Return the name of the device's devclass or @c NULL if there + * is none. + */ const char * device_get_name(device_t dev) { @@ -1421,24 +1710,38 @@ device_get_name(device_t dev) return (NULL); } +/** + * @brief Return a string containing the device's devclass name + * followed by an ascii representation of the device's unit number + * (e.g. @c "foo2"). + */ const char * device_get_nameunit(device_t dev) { return (dev->nameunit); } +/** + * @brief Return the device's unit number. + */ int device_get_unit(device_t dev) { return (dev->unit); } +/** + * @brief Return the device's description string + */ const char * device_get_desc(device_t dev) { return (dev->desc); } +/** + * @brief Return the device's flags + */ u_int32_t device_get_flags(device_t dev) { @@ -1457,6 +1760,11 @@ device_get_sysctl_tree(device_t dev) return (dev->sysctl_tree); } +/** + * @brief Print the name of the device followed by a colon and a space + * + * @returns the number of characters printed + */ int device_print_prettyname(device_t dev) { @@ -1467,6 +1775,13 @@ device_print_prettyname(device_t dev) return (printf("%s%d: ", name, device_get_unit(dev))); } +/** + * @brief Print the name of the device followed by a colon, a space + * and the result of calling vprintf() with the value of @p fmt and + * the following arguments. + * + * @returns the number of characters printed + */ int device_printf(device_t dev, const char * fmt, ...) { @@ -1480,6 +1795,9 @@ device_printf(device_t dev, const char * fmt, ...) return (retval); } +/** + * @internal + */ static void device_set_desc_internal(device_t dev, const char* desc, int copy) { @@ -1503,30 +1821,58 @@ device_set_desc_internal(device_t dev, const char* desc, int copy) bus_data_generation_update(); } +/** + * @brief Set the device's description + * + * The value of @c desc should be a string constant that will not + * change (at least until the description is changed in a subsequent + * call to device_set_desc() or device_set_desc_copy()). + */ void device_set_desc(device_t dev, const char* desc) { device_set_desc_internal(dev, desc, FALSE); } +/** + * @brief Set the device's description + * + * The string pointed to by @c desc is copied. Use this function if + * the device description is generated, (e.g. with sprintf()). + */ void device_set_desc_copy(device_t dev, const char* desc) { device_set_desc_internal(dev, desc, TRUE); } +/** + * @brief Set the device's flags + */ void device_set_flags(device_t dev, u_int32_t flags) { dev->devflags = flags; } +/** + * @brief Return the device's softc field + * + * The softc is allocated and zeroed when a driver is attached, based + * on the size field of the driver. + */ void * device_get_softc(device_t dev) { return (dev->softc); } +/** + * @brief Set the device's softc field + * + * Most drivers do not need to use this since the softc is allocated + * automatically when the driver is attached. + */ void device_set_softc(device_t dev, void *softc) { @@ -1539,6 +1885,13 @@ device_set_softc(device_t dev, void *softc) dev->flags &= ~DF_EXTERNALSOFTC; } +/** + * @brief Get the device's ivars field + * + * The ivars field is used by the parent device to store per-device + * state (e.g. the physical location of the device or a list of + * resources). + */ void * device_get_ivars(device_t dev) { @@ -1547,6 +1900,9 @@ device_get_ivars(device_t dev) return (dev->ivars); } +/** + * @brief Set the device's ivars field + */ void device_set_ivars(device_t dev, void * ivars) { @@ -1555,24 +1911,36 @@ device_set_ivars(device_t dev, void * ivars) dev->ivars = ivars; } +/** + * @brief Return the device's state + */ device_state_t device_get_state(device_t dev) { return (dev->state); } +/** + * @brief Set the DF_ENABLED flag for the device + */ void device_enable(device_t dev) { dev->flags |= DF_ENABLED; } +/** + * @brief Clear the DF_ENABLED flag for the device + */ void device_disable(device_t dev) { dev->flags &= ~DF_ENABLED; } +/** + * @brief Increment the busy counter for the device + */ void device_busy(device_t dev) { @@ -1584,6 +1952,9 @@ device_busy(device_t dev) dev->state = DS_BUSY; } +/** + * @brief Decrement the busy counter for the device + */ void device_unbusy(device_t dev) { @@ -1597,42 +1968,65 @@ device_unbusy(device_t dev) } } +/** + * @brief Set the DF_QUIET flag for the device + */ void device_quiet(device_t dev) { dev->flags |= DF_QUIET; } +/** + * @brief Clear the DF_QUIET flag for the device + */ void device_verbose(device_t dev) { dev->flags &= ~DF_QUIET; } +/** + * @brief Return non-zero if the DF_QUIET flag is set on the device + */ int device_is_quiet(device_t dev) { return ((dev->flags & DF_QUIET) != 0); } +/** + * @brief Return non-zero if the DF_ENABLED flag is set on the device + */ int device_is_enabled(device_t dev) { return ((dev->flags & DF_ENABLED) != 0); } +/** + * @brief Return non-zero if the device was successfully probed + */ int device_is_alive(device_t dev) { return (dev->state >= DS_ALIVE); } +/** + * @brief Return non-zero if the device currently has a driver + * attached to it + */ int device_is_attached(device_t dev) { return (dev->state >= DS_ATTACHED); } +/** + * @brief Set the devclass of a device + * @see devclass_add_device(). + */ int device_set_devclass(device_t dev, const char *classname) { @@ -1660,6 +2054,13 @@ device_set_devclass(device_t dev, const char *classname) return (error); } +/** + * @brief Set the driver of a device + * + * @retval 0 success + * @retval EBUSY the device already has a driver attached + * @retval ENOMEM a memory allocation failure occurred + */ int device_set_driver(device_t dev, driver_t *driver) { @@ -1695,6 +2096,32 @@ device_set_driver(device_t dev, driver_t *driver) return (0); } +/** + * @brief Probe a device and attach a driver if possible + * + * This function is the core of the device autoconfiguration + * system. Its purpose is to select a suitable driver for a device and + * then call that driver to initialise the hardware appropriately. The + * driver is selected by calling the DEVICE_PROBE() method of a set of + * candidate drivers and then choosing the driver which returned the + * best value. This driver is then attached to the device using + * device_attach(). + * + * The set of suitable drivers is taken from the list of drivers in + * the parent device's devclass. If the device was originally created + * with a specific class name (see device_add_child()), only drivers + * with that name are probed, otherwise all drivers in the devclass + * are probed. If no drivers return successful probe values in the + * parent devclass, the search continues in the parent of that + * devclass (see devclass_get_parent()) if any. + * + * @param dev the device to initialise + * + * @retval 0 success + * @retval ENXIO no driver was found + * @retval ENOMEM memory allocation failure + * @retval non-zero some other unix error code + */ int device_probe_and_attach(device_t dev) { @@ -1723,6 +2150,25 @@ device_probe_and_attach(device_t dev) return (error); } +/** + * @brief Attach a device driver to a device + * + * This function is a wrapper around the DEVICE_ATTACH() driver + * method. In addition to calling DEVICE_ATTACH(), it initialises the + * device's sysctl tree, optionally prints a description of the device + * and queues a notification event for user-based device management + * services. + * + * Normally this function is only called internally from + * device_probe_and_attach(). + * + * @param dev the device to initialise + * + * @retval 0 success + * @retval ENXIO no driver was found + * @retval ENOMEM memory allocation failure + * @retval non-zero some other unix error code + */ int device_attach(device_t dev) { @@ -1747,6 +2193,22 @@ device_attach(device_t dev) return (0); } +/** + * @brief Detach a driver from a device + * + * This function is a wrapper around the DEVICE_DETACH() driver + * method. If the call to DEVICE_DETACH() succeeds, it calls + * BUS_CHILD_DETACHED() for the parent of @p dev, queues a + * notification event for user-based device management services and + * cleans up the device's sysctl tree. + * + * @param dev the device to un-initialise + * + * @retval 0 success + * @retval ENXIO no driver was found + * @retval ENOMEM memory allocation failure + * @retval non-zero some other unix error code + */ int device_detach(device_t dev) { @@ -1775,6 +2237,14 @@ device_detach(device_t dev) return (0); } +/** + * @brief Notify a device of system shutdown + * + * This function calls the DEVICE_SHUTDOWN() driver method if the + * device currently has an attached driver. + * + * @returns the value returned by DEVICE_SHUTDOWN() + */ int device_shutdown(device_t dev) { @@ -1783,6 +2253,12 @@ device_shutdown(device_t dev) return (DEVICE_SHUTDOWN(dev)); } +/** + * @brief Set the unit number of a device + * + * This function can be used to override the unit number used for a + * device (e.g. to wire a device to a pre-configured unit number). + */ int device_set_unit(device_t dev, int unit) { @@ -1809,12 +2285,25 @@ device_set_unit(device_t dev, int unit) * Some useful method implementations to make life easier for bus drivers. */ +/** + * @brief Initialise a resource list. + * + * @param rl the resource list to initialise + */ void resource_list_init(struct resource_list *rl) { SLIST_INIT(rl); } +/** + * @brief Reclaim memory used by a resource list. + * + * This function frees the memory for all resource entries on the list + * (if any). + * + * @param rl the resource list to free + */ void resource_list_free(struct resource_list *rl) { @@ -1828,6 +2317,19 @@ resource_list_free(struct resource_list *rl) } } +/** + * @brief Add a resource entry. + * + * This function adds a resource entry using the given @p type, @p + * start, @p end and @p count values. A rid value is chosen by + * searching sequentially for the first unused rid starting at zero. + * + * @param rl the resource list to edit + * @param type the resource entry type (e.g. SYS_RES_MEMORY) + * @param start the start address of the resource + * @param end the end address of the resource + * @param count XXX end-start+1 + */ int resource_list_add_next(struct resource_list *rl, int type, u_long start, u_long end, u_long count) @@ -1841,6 +2343,21 @@ resource_list_add_next(struct resource_list *rl, int type, u_long start, return (rid); } +/** + * @brief Add or modify a resource entry. + * + * If an existing entry exists with the same type and rid, it will be + * modified using the given values of @p start, @p end and @p + * count. If no entry exists, a new one will be created using the + * given values. + * + * @param rl the resource list to edit + * @param type the resource entry type (e.g. SYS_RES_MEMORY) + * @param rid the resource identifier + * @param start the start address of the resource + * @param end the end address of the resource + * @param count XXX end-start+1 + */ void resource_list_add(struct resource_list *rl, int type, int rid, u_long start, u_long end, u_long count) @@ -1867,6 +2384,16 @@ resource_list_add(struct resource_list *rl, int type, int rid, rle->count = count; } +/** + * @brief Find a resource entry by type and rid. + * + * @param rl the resource list to search + * @param type the resource entry type (e.g. SYS_RES_MEMORY) + * @param rid the resource identifier + * + * @returns the resource entry pointer or NULL if there is no such + * entry. + */ struct resource_list_entry * resource_list_find(struct resource_list *rl, int type, int rid) { @@ -1879,6 +2406,13 @@ resource_list_find(struct resource_list *rl, int type, int rid) return (NULL); } +/** + * @brief Delete a resource entry. + * + * @param rl the resource list to edit + * @param type the resource entry type (e.g. SYS_RES_MEMORY) + * @param rid the resource identifier + */ void resource_list_delete(struct resource_list *rl, int type, int rid) { @@ -1892,6 +2426,39 @@ resource_list_delete(struct resource_list *rl, int type, int rid) } } +/** + * @brief Helper function for implementing BUS_ALLOC_RESOURCE() + * + * Implement BUS_ALLOC_RESOURCE() by looking up a resource from the list + * and passing the allocation up to the parent of @p bus. This assumes + * that the first entry of @c device_get_ivars(child) is a struct + * resource_list. This also handles 'passthrough' allocations where a + * child is a remote descendant of bus by passing the allocation up to + * the parent of bus. + * + * Typically, a bus driver would store a list of child resources + * somewhere in the child device's ivars (see device_get_ivars()) and + * its implementation of BUS_ALLOC_RESOURCE() would find that list and + * then call resource_list_alloc() to perform the allocation. + * + * @param rl the resource list to allocate from + * @param bus the parent device of @p child + * @param child the device which is requesting an allocation + * @param type the type of resource to allocate + * @param rid a pointer to the resource identifier + * @param start hint at the start of the resource range - pass + * @c 0UL for any start address + * @param end hint at the end of the resource range - pass + * @c ~0UL for any end address + * @param count hint at the size of range required - pass @c 1 + * for any size + * @param flags any extra flags to control the resource + * allocation - see @c RF_XXX flags in + * <sys/rman.h> for details + * + * @returns the resource which was allocated or @c NULL if no + * resource could be allocated + */ struct resource * resource_list_alloc(struct resource_list *rl, device_t bus, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) @@ -1934,6 +2501,23 @@ resource_list_alloc(struct resource_list *rl, device_t bus, device_t child, return (rle->res); } +/** + * @brief Helper function for implementing BUS_RELEASE_RESOURCE() + * + * Implement BUS_RELEASE_RESOURCE() using a resource list. Normally + * used with resource_list_alloc(). + * + * @param rl the resource list which was allocated from + * @param bus the parent device of @p child + * @param child the device which is requesting a release + * @param type the type of resource to allocate + * @param rid the resource identifier + * @param res the resource to release + * + * @retval 0 success + * @retval non-zero a standard unix error code indicating what + * error condition prevented the operation + */ int resource_list_release(struct resource_list *rl, device_t bus, device_t child, int type, int rid, struct resource *res) @@ -1963,6 +2547,21 @@ resource_list_release(struct resource_list *rl, device_t bus, device_t child, return (0); } +/** + * @brief Print a description of resources in a resource list + * + * Print all resources of a specified type, for use in BUS_PRINT_CHILD(). + * The name is printed if at least one resource of the given type is available. + * The format is used to print resource start and end. + * + * @param rl the resource list to print + * @param name the name of @p type, e.g. @c "memory" + * @param type type type of resource entry to print + * @param format printf(9) format string to print resource + * start and end values + * + * @returns the number of characters printed + */ int resource_list_print_type(struct resource_list *rl, const char *name, int type, const char *format) @@ -1991,8 +2590,13 @@ resource_list_print_type(struct resource_list *rl, const char *name, int type, return (retval); } -/* - * Call DEVICE_IDENTIFY for each driver. +/** + * @brief Helper function for implementing DEVICE_PROBE() + * + * This function can be used to help implement the DEVICE_PROBE() for + * a bus (i.e. a device which has other devices attached to it). It + * calls the DEVICE_IDENTIFY() method of each driver in the device's + * devclass. */ int bus_generic_probe(device_t dev) @@ -2007,6 +2611,13 @@ bus_generic_probe(device_t dev) return (0); } +/** + * @brief Helper function for implementing DEVICE_ATTACH() + * + * This function can be used to help implement the DEVICE_ATTACH() for + * a bus. It calls device_probe_and_attach() for each of the device's + * children. + */ int bus_generic_attach(device_t dev) { @@ -2019,6 +2630,13 @@ bus_generic_attach(device_t dev) return (0); } +/** + * @brief Helper function for implementing DEVICE_DETACH() + * + * This function can be used to help implement the DEVICE_DETACH() for + * a bus. It calls device_detach() for each of the device's + * children. + */ int bus_generic_detach(device_t dev) { @@ -2036,6 +2654,13 @@ bus_generic_detach(device_t dev) return (0); } +/** + * @brief Helper function for implementing DEVICE_SHUTDOWN() + * + * This function can be used to help implement the DEVICE_SHUTDOWN() + * for a bus. It calls device_shutdown() for each of the device's + * children. + */ int bus_generic_shutdown(device_t dev) { @@ -2048,6 +2673,15 @@ bus_generic_shutdown(device_t dev) return (0); } +/** + * @brief Helper function for implementing DEVICE_SUSPEND() + * + * This function can be used to help implement the DEVICE_SUSPEND() + * for a bus. It calls DEVICE_SUSPEND() for each of the device's + * children. If any call to DEVICE_SUSPEND() fails, the suspend + * operation is aborted and any devices which were suspended are + * resumed immediately by calling their DEVICE_RESUME() methods. + */ int bus_generic_suspend(device_t dev) { @@ -2067,6 +2701,12 @@ bus_generic_suspend(device_t dev) return (0); } +/** + * @brief Helper function for implementing DEVICE_RESUME() + * + * This function can be used to help implement the DEVICE_RESUME() for + * a bus. It calls DEVICE_RESUME() on each of the device's children. + */ int bus_generic_resume(device_t dev) { @@ -2079,6 +2719,15 @@ bus_generic_resume(device_t dev) return (0); } +/** + * @brief Helper function for implementing BUS_PRINT_CHILD(). + * + * This function prints the first part of the ascii representation of + * @p child, including its name, unit and description (if any - see + * device_set_desc()). + * + * @returns the number of characters printed + */ int bus_print_child_header(device_t dev, device_t child) { @@ -2093,12 +2742,29 @@ bus_print_child_header(device_t dev, device_t child) return (retval); } +/** + * @brief Helper function for implementing BUS_PRINT_CHILD(). + * + * This function prints the last part of the ascii representation of + * @p child, which consists of the string @c " on " followed by the + * name and unit of the @p dev. + * + * @returns the number of characters printed + */ int bus_print_child_footer(device_t dev, device_t child) { return (printf(" on %s\n", device_get_nameunit(dev))); } +/** + * @brief Helper function for implementing BUS_PRINT_CHILD(). + * + * This function simply calls bus_print_child_header() followed by + * bus_print_child_footer(). + * + * @returns the number of characters printed + */ int bus_generic_print_child(device_t dev, device_t child) { @@ -2110,6 +2776,11 @@ bus_generic_print_child(device_t dev, device_t child) return (retval); } +/** + * @brief Stub function for implementing BUS_READ_IVAR(). + * + * @returns ENOENT + */ int bus_generic_read_ivar(device_t dev, device_t child, int index, uintptr_t * result) @@ -2117,6 +2788,11 @@ bus_generic_read_ivar(device_t dev, device_t child, int index, return (ENOENT); } +/** + * @brief Stub function for implementing BUS_WRITE_IVAR(). + * + * @returns ENOENT + */ int bus_generic_write_ivar(device_t dev, device_t child, int index, uintptr_t value) @@ -2124,12 +2800,24 @@ bus_generic_write_ivar(device_t dev, device_t child, int index, return (ENOENT); } +/** + * @brief Stub function for implementing BUS_GET_RESOURCE_LIST(). + * + * @returns NULL + */ struct resource_list * bus_generic_get_resource_list(device_t dev, device_t child) { return (NULL); } +/** + * @brief Helper function for implementing BUS_DRIVER_ADDED(). + * + * This implementation of BUS_DRIVER_ADDED() simply calls the driver's + * DEVICE_IDENTIFY() method to allow it to add new children to the bus + * and then calls device_probe_and_attach() for each unattached child. + */ void bus_generic_driver_added(device_t dev, driver_t *driver) { @@ -2142,6 +2830,12 @@ bus_generic_driver_added(device_t dev, driver_t *driver) } } +/** + * @brief Helper function for implementing BUS_SETUP_INTR(). + * + * This simple implementation of BUS_SETUP_INTR() simply calls the + * BUS_SETUP_INTR() method of the parent of @p dev. + */ int bus_generic_setup_intr(device_t dev, device_t child, struct resource *irq, int flags, driver_intr_t *intr, void *arg, void **cookiep) @@ -2153,6 +2847,12 @@ bus_generic_setup_intr(device_t dev, device_t child, struct resource *irq, return (EINVAL); } +/** + * @brief Helper function for implementing BUS_TEARDOWN_INTR(). + * + * This simple implementation of BUS_TEARDOWN_INTR() simply calls the + * BUS_TEARDOWN_INTR() method of the parent of @p dev. + */ int bus_generic_teardown_intr(device_t dev, device_t child, struct resource *irq, void *cookie) @@ -2163,6 +2863,12 @@ bus_generic_teardown_intr(device_t dev, device_t child, struct resource *irq, return (EINVAL); } +/** + * @brief Helper function for implementing BUS_ALLOC_RESOURCE(). + * + * This simple implementation of BUS_ALLOC_RESOURCE() simply calls the + * BUS_ALLOC_RESOURCE() method of the parent of @p dev. + */ struct resource * bus_generic_alloc_resource(device_t dev, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) @@ -2174,6 +2880,12 @@ bus_generic_alloc_resource(device_t dev, device_t child, int type, int *rid, return (NULL); } +/** + * @brief Helper function for implementing BUS_RELEASE_RESOURCE(). + * + * This simple implementation of BUS_RELEASE_RESOURCE() simply calls the + * BUS_RELEASE_RESOURCE() method of the parent of @p dev. + */ int bus_generic_release_resource(device_t dev, device_t child, int type, int rid, struct resource *r) @@ -2185,6 +2897,12 @@ bus_generic_release_resource(device_t dev, device_t child, int type, int rid, return (EINVAL); } +/** + * @brief Helper function for implementing BUS_ACTIVATE_RESOURCE(). + * + * This simple implementation of BUS_ACTIVATE_RESOURCE() simply calls the + * BUS_ACTIVATE_RESOURCE() method of the parent of @p dev. + */ int bus_generic_activate_resource(device_t dev, device_t child, int type, int rid, struct resource *r) @@ -2196,6 +2914,12 @@ bus_generic_activate_resource(device_t dev, device_t child, int type, int rid, return (EINVAL); } +/** + * @brief Helper function for implementing BUS_DEACTIVATE_RESOURCE(). + * + * This simple implementation of BUS_DEACTIVATE_RESOURCE() simply calls the + * BUS_DEACTIVATE_RESOURCE() method of the parent of @p dev. + */ int bus_generic_deactivate_resource(device_t dev, device_t child, int type, int rid, struct resource *r) @@ -2207,6 +2931,12 @@ bus_generic_deactivate_resource(device_t dev, device_t child, int type, return (EINVAL); } +/** + * @brief Helper function for implementing BUS_CONFIG_INTR(). + * + * This simple implementation of BUS_CONFIG_INTR() simply calls the + * BUS_CONFIG_INTR() method of the parent of @p dev. + */ int bus_generic_config_intr(device_t dev, int irq, enum intr_trigger trig, enum intr_polarity pol) @@ -2218,6 +2948,14 @@ bus_generic_config_intr(device_t dev, int irq, enum intr_trigger trig, return (EINVAL); } +/** + * @brief Helper function for implementing BUS_GET_RESOURCE(). + * + * This implementation of BUS_GET_RESOURCE() uses the + * resource_list_find() function to do most of the work. It calls + * BUS_GET_RESOURCE_LIST() to find a suitable resource list to + * search. + */ int bus_generic_rl_get_resource(device_t dev, device_t child, int type, int rid, u_long *startp, u_long *countp) @@ -2241,6 +2979,14 @@ bus_generic_rl_get_resource(device_t dev, device_t child, int type, int rid, return (0); } +/** + * @brief Helper function for implementing BUS_SET_RESOURCE(). + * + * This implementation of BUS_SET_RESOURCE() uses the + * resource_list_add() function to do most of the work. It calls + * BUS_GET_RESOURCE_LIST() to find a suitable resource list to + * edit. + */ int bus_generic_rl_set_resource(device_t dev, device_t child, int type, int rid, u_long start, u_long count) @@ -2256,6 +3002,14 @@ bus_generic_rl_set_resource(device_t dev, device_t child, int type, int rid, return (0); } +/** + * @brief Helper function for implementing BUS_DELETE_RESOURCE(). + * + * This implementation of BUS_DELETE_RESOURCE() uses the + * resource_list_delete() function to do most of the work. It calls + * BUS_GET_RESOURCE_LIST() to find a suitable resource list to + * edit. + */ void bus_generic_rl_delete_resource(device_t dev, device_t child, int type, int rid) { @@ -2270,6 +3024,13 @@ bus_generic_rl_delete_resource(device_t dev, device_t child, int type, int rid) return; } +/** + * @brief Helper function for implementing BUS_RELEASE_RESOURCE(). + * + * This implementation of BUS_RELEASE_RESOURCE() uses the + * resource_list_release() function to do most of the work. It calls + * BUS_GET_RESOURCE_LIST() to find a suitable resource list. + */ int bus_generic_rl_release_resource(device_t dev, device_t child, int type, int rid, struct resource *r) @@ -2283,6 +3044,13 @@ bus_generic_rl_release_resource(device_t dev, device_t child, int type, return (resource_list_release(rl, dev, child, type, rid, r)); } +/** + * @brief Helper function for implementing BUS_ALLOC_RESOURCE(). + * + * This implementation of BUS_ALLOC_RESOURCE() uses the + * resource_list_alloc() function to do most of the work. It calls + * BUS_GET_RESOURCE_LIST() to find a suitable resource list. + */ struct resource * bus_generic_rl_alloc_resource(device_t dev, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) @@ -2297,10 +3065,16 @@ bus_generic_rl_alloc_resource(device_t dev, device_t child, int type, start, end, count, flags)); } +/** + * @brief Helper function for implementing BUS_CHILD_PRESENT(). + * + * This simple implementation of BUS_CHILD_PRESENT() simply calls the + * BUS_CHILD_PRESENT() method of the parent of @p dev. + */ int -bus_generic_child_present(device_t bus, device_t child) +bus_generic_child_present(device_t dev, device_t child) { - return (BUS_CHILD_PRESENT(device_get_parent(bus), bus)); + return (BUS_CHILD_PRESENT(device_get_parent(dev), dev)); } /* @@ -2310,6 +3084,13 @@ bus_generic_child_present(device_t bus, device_t child) * less-wordy code. In the future, it might make sense for this code * to maintain some sort of a list of resources allocated by each device. */ + +/** + * @brief Wrapper function for BUS_ALLOC_RESOURCE(). + * + * This function simply calls the BUS_ALLOC_RESOURCE() method of the + * parent of @p dev. + */ struct resource * bus_alloc_resource(device_t dev, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) @@ -2320,6 +3101,12 @@ bus_alloc_resource(device_t dev, int type, int *rid, u_long start, u_long end, count, flags)); } +/** + * @brief Wrapper function for BUS_ACTIVATE_RESOURCE(). + * + * This function simply calls the BUS_ACTIVATE_RESOURCE() method of the + * parent of @p dev. + */ int bus_activate_resource(device_t dev, int type, int rid, struct resource *r) { @@ -2328,6 +3115,12 @@ bus_activate_resource(device_t dev, int type, int rid, struct resource *r) return (BUS_ACTIVATE_RESOURCE(dev->parent, dev, type, rid, r)); } +/** + * @brief Wrapper function for BUS_DEACTIVATE_RESOURCE(). + * + * This function simply calls the BUS_DEACTIVATE_RESOURCE() method of the + * parent of @p dev. + */ int bus_deactivate_resource(device_t dev, int type, int rid, struct resource *r) { @@ -2336,6 +3129,12 @@ bus_deactivate_resource(device_t dev, int type, int rid, struct resource *r) return (BUS_DEACTIVATE_RESOURCE(dev->parent, dev, type, rid, r)); } +/** + * @brief Wrapper function for BUS_RELEASE_RESOURCE(). + * + * This function simply calls the BUS_RELEASE_RESOURCE() method of the + * parent of @p dev. + */ int bus_release_resource(device_t dev, int type, int rid, struct resource *r) { @@ -2344,6 +3143,12 @@ bus_release_resource(device_t dev, int type, int rid, struct resource *r) return (BUS_RELEASE_RESOURCE(dev->parent, dev, type, rid, r)); } +/** + * @brief Wrapper function for BUS_SETUP_INTR(). + * + * This function simply calls the BUS_SETUP_INTR() method of the + * parent of @p dev. + */ int bus_setup_intr(device_t dev, struct resource *r, int flags, driver_intr_t handler, void *arg, void **cookiep) @@ -2369,6 +3174,12 @@ bus_setup_intr(device_t dev, struct resource *r, int flags, return (error); } +/** + * @brief Wrapper function for BUS_TEARDOWN_INTR(). + * + * This function simply calls the BUS_TEARDOWN_INTR() method of the + * parent of @p dev. + */ int bus_teardown_intr(device_t dev, struct resource *r, void *cookie) { @@ -2377,6 +3188,12 @@ bus_teardown_intr(device_t dev, struct resource *r, void *cookie) return (BUS_TEARDOWN_INTR(dev->parent, dev, r, cookie)); } +/** + * @brief Wrapper function for BUS_SET_RESOURCE(). + * + * This function simply calls the BUS_SET_RESOURCE() method of the + * parent of @p dev. + */ int bus_set_resource(device_t dev, int type, int rid, u_long start, u_long count) @@ -2385,6 +3202,12 @@ bus_set_resource(device_t dev, int type, int rid, start, count)); } +/** + * @brief Wrapper function for BUS_GET_RESOURCE(). + * + * This function simply calls the BUS_GET_RESOURCE() method of the + * parent of @p dev. + */ int bus_get_resource(device_t dev, int type, int rid, u_long *startp, u_long *countp) @@ -2393,6 +3216,12 @@ bus_get_resource(device_t dev, int type, int rid, startp, countp)); } +/** + * @brief Wrapper function for BUS_GET_RESOURCE(). + * + * This function simply calls the BUS_GET_RESOURCE() method of the + * parent of @p dev and returns the start value. + */ u_long bus_get_resource_start(device_t dev, int type, int rid) { @@ -2406,6 +3235,12 @@ bus_get_resource_start(device_t dev, int type, int rid) return (start); } +/** + * @brief Wrapper function for BUS_GET_RESOURCE(). + * + * This function simply calls the BUS_GET_RESOURCE() method of the + * parent of @p dev and returns the count value. + */ u_long bus_get_resource_count(device_t dev, int type, int rid) { @@ -2419,18 +3254,36 @@ bus_get_resource_count(device_t dev, int type, int rid) return (count); } +/** + * @brief Wrapper function for BUS_DELETE_RESOURCE(). + * + * This function simply calls the BUS_DELETE_RESOURCE() method of the + * parent of @p dev. + */ void bus_delete_resource(device_t dev, int type, int rid) { BUS_DELETE_RESOURCE(device_get_parent(dev), dev, type, rid); } +/** + * @brief Wrapper function for BUS_CHILD_PRESENT(). + * + * This function simply calls the BUS_CHILD_PRESENT() method of the + * parent of @p dev. + */ int bus_child_present(device_t child) { return (BUS_CHILD_PRESENT(device_get_parent(child), child)); } +/** + * @brief Wrapper function for BUS_CHILD_PNPINFO_STR(). + * + * This function simply calls the BUS_CHILD_PNPINFO_STR() method of the + * parent of @p dev. + */ int bus_child_pnpinfo_str(device_t child, char *buf, size_t buflen) { @@ -2444,6 +3297,12 @@ bus_child_pnpinfo_str(device_t child, char *buf, size_t buflen) return (BUS_CHILD_PNPINFO_STR(parent, child, buf, buflen)); } +/** + * @brief Wrapper function for BUS_CHILD_LOCATION_STR(). + * + * This function simply calls the BUS_CHILD_LOCATION_STR() method of the + * parent of @p dev. + */ int bus_child_location_str(device_t child, char *buf, size_t buflen) { @@ -2549,6 +3408,12 @@ static moduledata_t root_bus_mod = { }; DECLARE_MODULE(rootbus, root_bus_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); +/** + * @brief Automatically configure devices + * + * This function begins the autoconfiguration process by calling + * device_probe_and_attach() for each child of the @c root0 device. + */ void root_bus_configure(void) { @@ -2561,6 +3426,14 @@ root_bus_configure(void) } } +/** + * @brief Module handler for registering device drivers + * + * This module handler is used to automatically register device + * drivers when modules are loaded. If @p what is MOD_LOAD, it calls + * devclass_add_driver() for the driver described by the + * driver_module_data structure pointed to by @p arg + */ int driver_module_handler(module_t mod, int what, void *arg) { |