* @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 succ
| 2994 | * @retval non-zero some other unix error code |
| 2995 | */ |
| 2996 | int |
| 2997 | device_detach(device_t dev) |
| 2998 | { |
| 2999 | int error; |
| 3000 | |
| 3001 | GIANT_REQUIRED; |
| 3002 | |
| 3003 | PDEBUG(("%s", DEVICENAME(dev))); |
| 3004 | if (dev->state == DS_BUSY) |
| 3005 | return (EBUSY); |
| 3006 | if (dev->state == DS_ATTACHING) { |
| 3007 | device_printf(dev, "device in attaching state! Deferring detach.\n"); |
| 3008 | return (EBUSY); |
| 3009 | } |
| 3010 | if (dev->state != DS_ATTACHED) |
| 3011 | return (0); |
| 3012 | |
| 3013 | EVENTHANDLER_DIRECT_INVOKE(device_detach, dev, EVHDEV_DETACH_BEGIN); |
| 3014 | if ((error = DEVICE_DETACH(dev)) != 0) { |
| 3015 | EVENTHANDLER_DIRECT_INVOKE(device_detach, dev, |
| 3016 | EVHDEV_DETACH_FAILED); |
| 3017 | return (error); |
| 3018 | } else { |
| 3019 | EVENTHANDLER_DIRECT_INVOKE(device_detach, dev, |
| 3020 | EVHDEV_DETACH_COMPLETE); |
| 3021 | } |
| 3022 | devremoved(dev); |
| 3023 | if (!device_is_quiet(dev)) |
| 3024 | device_printf(dev, "detached\n"); |
| 3025 | if (dev->parent) |
| 3026 | BUS_CHILD_DETACHED(dev->parent, dev); |
| 3027 | |
| 3028 | if (!(dev->flags & DF_FIXEDCLASS)) |
| 3029 | devclass_delete_device(dev->devclass, dev); |
| 3030 | |
| 3031 | device_verbose(dev); |
| 3032 | dev->state = DS_NOTPRESENT; |
| 3033 | (void)device_set_driver(dev, NULL); |
| 3034 | device_sysctl_fini(dev); |
| 3035 | |
| 3036 | return (0); |
| 3037 | } |
| 3038 | |
| 3039 | /** |
| 3040 | * @brief Tells a driver to quiesce itself. |
no test coverage detected