Date: Mon, 9 Jul 2007 18:08:23 GMT From: Maxim Zhuravlev <thioretic@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 123220 for review Message-ID: <200707091808.l69I8Nm2089870@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=123220 Change 123220 by thioretic@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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200707091808.l69I8Nm2089870>