PERFORCE change 123220 for review
Maxim Zhuravlev
thioretic at FreeBSD.org
Mon Jul 9 18:08:24 UTC 2007
http://perforce.freebsd.org/chv.cgi?CH=123220
Change 123220 by thioretic at thioretic on 2007/07/09 18:08:19
TODO: softc, device_set_driver semantics
and some cleanups.
DONE: unified parents/children manipulation
Affected files ...
.. //depot/projects/soc2007/thioretic_gidl/kern/subr_bus.c#11 edit
Differences ...
==== //depot/projects/soc2007/thioretic_gidl/kern/subr_bus.c#11 (text+ko) ====
@@ -2038,7 +2038,47 @@
return (device_add_child_ordered(dev, 0, name, unit));
}
+static int
+device_add_to_dev_list (device_t addwhat, pdevice_list_t *addwhere){
+ pdevice *pd;
+ TAILQ_FOREACH (pd, addwhere, link){
+ if (pd->device_ptr == addwhat)
+ return (1);
+ }
+
+ pd = malloc(sizeof(struct pdevice), M_BUS, M_NOWAIT|M_ZERO);
+ if (!pd)
+ return (0);
+
+ pd->device_ptr = addwhat;
+ TAILQ_INSERT_TAIL(addwhere, pd, link);
+ pd->device_ptr->refs++;
+
+ bus_data_generation_update();
+ return (1);
+}
+
/**
+ * @brief Add a new child, which is a device, that already exists
+ *
+ * This adds a new parent (if not yet in parents)
+ */
+int
+device_add_existing_child (device_t dev, device_t child){
+ device_add_to_dev_list (child, &(dev->children));
+}
+/**
+ * @brief Add a new parent, which is a device, that already exists
+ *
+ * This adds a new parent (if not yet in parents)
+ */
+int
+device_add_existing_parent (device_t dev, device_t parent){
+ device_add_to_dev_list (parent, &(dev->parents));
+}
+
+
+/**
* @brief Create a new device
*
* This creates a new device and adds it as a child of an existing
@@ -2099,72 +2139,105 @@
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) /*TODO*/
-{
+#define CHILDREN -1
+#define PARENTS 1
+
+static int
+destroy_recurse (device_t dev, device_t devtodel, int direction){
int error;
- /*device_t*/ pdevice *grandchild;
+ pdevice *grand;
pdevice *pd;
+ pdevice_list_t *list;
PDEBUG(("%s from %s", DEVICENAME(child), DEVICENAME(dev)));
- child->refs--;
- if (child->refs) goto deletefromparent;
/* remove children first */
- while ( (grandchild = TAILQ_FIRST(&child->children)) ) {
- error = device_delete_child(child, grandchild->device_ptr);
+ list = (direction == CHILDREN) ? &devtodel->children : &devtodel->parents;
+ if (--devtodel->refs) goto deleteself;
+ while ( (grand = TAILQ_FIRST(list)) ) {
+ error = destroy_recurse(devtodel, grand->device_ptr, direction);
if (error)
return (error);
- free (grandchild);
+ free (grand);
}
- if ((error = device_detach(child)) != 0)
+ if ((error = device_detach(devtodel)) != 0)
return (error);
- if (child->devclass)
- devclass_delete_device(child->devclass, child);
+ if (devtodel->devclass)
+ devclass_delete_device(devtodel->devclass, devtodel);
deletefromparent:
- TAILQ_FOREACH_SAFE(pd, &dev->children, link){
- if (pd->device_ptr == child){
- TAILQ_REMOVE(&dev->children, child, link);
+ TAILQ_FOREACH_SAFE(pd, list, link){
+ if (pd->device_ptr == devtodel){
+ TAILQ_REMOVE(list, devtodel, link);
free (pd);
break;
}
}
- if (child->refs)
+ if (devtodel->refs)
return (0);
- TAILQ_REMOVE(&bus_data_devices, child, devlink);
- kobj_delete((kobj_t) child, M_BUS);
+ TAILQ_REMOVE(&bus_data_devices, devtodel, devlink);
+ kobj_delete((kobj_t) devtodel, M_BUS);
bus_data_generation_update();
return (0);
}
+
+void
+device_delete_existing_child (device_t dev, device_t child){
+ destroy_recurse (dev, child, CHILDREN);
+}
+
+void
+device_add_existing_parent (device_t dev, device_t parent){
+ destroy_recurse (dev, parent, PARENTS);
+}
+
+/**
+ * @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) /*TODO*/
+{
+ return (destroy_recurse(dev, child, CHILDREN));
+}
+
static int
-is_device_parent (device_t dev, device_t child){
+is_device_relation (device_t dev, device_t tocheck, int direction){
pdevice *dc;
- TAILQ_FOREACH (dc, &(child->parents), link){
+ pdevice_list_t list;
+
+ list = (direction == CHILDREN) ? &tocheck->parents : &tocheck->children;
+ TAILQ_FOREACH (dc, list, link){
if (dc->device_ptr == dev) return (TRUE);
}
return (FALSE);
}
+static int
+is_device_child (device_t dev, device_t child){
+ return (is_device_relation(dev, child, CHILDREN));
+}
+
+static int
+is_device_parent (device_t dev, device_t parent){
+ return (is_device_relation(dev, parent, PARENTS));
+}
+
/**
- * @brief Find a device given a unit number
+ * @brief Find a relation device given a unit number
*
* This is similar to devclass_get_devices() but only searches for
* devices which have @p dev as a parent.
@@ -2178,31 +2251,43 @@
* NULL if there is no such device
*/
device_t
-device_find_child(device_t dev, const char *classname, int unit)
+device_find_relation(device_t dev, const char *classname, int unit, int direction)
{
devclass_t dc;
- device_t child;
+ device_t relation;
dc = devclass_find(classname);
if (!dc)
return (NULL);
if (unit != -1) {
- child = devclass_get_device(dc, unit);
- if (child && /*child->parent == dev*/
- is_device_parent(dev, child))
- return (child);
+ relation = devclass_get_device(dc, unit);
+ if (relation &&
+ ((direction==CHILDREN) ? is_device_child(dev, relation) :
+ is_device_parent(dev, relation)))
+ return (relation);
} else {
for (unit = 0; unit < devclass_get_maxunit(dc); unit++) {
- child = devclass_get_device(dc, unit);
- if (child && /*child->parent == dev*/
- is_device_parent(dev, child))
- return (child);
+ relation = devclass_get_device(dc, unit);
+ if (relation &&
+ ((direction==CHILDREN) ? is_device_child(dev, relation) :
+ is_device_parent(dev, relation)))
+ return (relation);
}
}
return (NULL);
}
+device_t
+device_find_child(device_t dev, const char* classname, int unit){
+ return (device_find_relation (dev, classname, unit, CHILDREN));
+}
+
+device_t
+device_find_parent(device_t dev, const char* classname, int unit){
+ return (device_find_relation (dev, classname, unit, PARENTS));
+}
+
/**
* @internal
*/
@@ -2403,14 +2488,16 @@
* @retval ENOMEM the array allocation failed
*/
int
-device_get_children(device_t dev, device_t **devlistp, int *devcountp)
+device_get_relations(device_t dev, device_t **devlistp, int *devcountp, int direction)
{
int count;
- /*device_t*/ pdevice *child;
+ /*device_t*/ pdevice *relation;
device_t *list;
+ pdevice_list_t wherelist;
+ wherelist = (direction == CHILDREN) : &dev->children : &dev->parents;
count = 0;
- TAILQ_FOREACH(child, &dev->children, link) {
+ TAILQ_FOREACH(relation, wherelist, link) {
count++;
}
@@ -2419,8 +2506,8 @@
return (ENOMEM);
count = 0;
- TAILQ_FOREACH(child, &dev->children, link) {
- list[count] = child->device_ptr;
+ TAILQ_FOREACH(relation, wherelist, link) {
+ list[count] = relation->device_ptr;
count++;
}
@@ -2430,6 +2517,16 @@
return (0);
}
+int
+device_get_children(device_t dev, device_t **devlistp, int *devcountp){
+ return (device_get_relations(dev, devlistp, devcountp, CHILDREN));
+}
+
+int
+device_get_all_parents(device_t dev, device_t **devlistp, int *devcountp){
+ return (device_get_relations(dev, devlistp, devcountp, PARENTS));
+}
+
/**
* @brief Return the current driver for the device or @c NULL if there
* is no driver currently attached
More information about the p4-projects
mailing list