Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:16

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /* Driver Manager Device Unregister (removal) implementation
0004  *
0005  * COPYRIGHT (c) 2011 Cobham Gaisler AB.
0006  *
0007  * Redistribution and use in source and binary forms, with or without
0008  * modification, are permitted provided that the following conditions
0009  * are met:
0010  * 1. Redistributions of source code must retain the above copyright
0011  *    notice, this list of conditions and the following disclaimer.
0012  * 2. Redistributions in binary form must reproduce the above copyright
0013  *    notice, this list of conditions and the following disclaimer in the
0014  *    documentation and/or other materials provided with the distribution.
0015  *
0016  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0017  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0018  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0019  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0020  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0021  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0022  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0023  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0024  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0025  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0026  * POSSIBILITY OF SUCH DAMAGE.
0027  */
0028 
0029 #include <stdlib.h>
0030 
0031 #include <drvmgr/drvmgr.h>
0032 #include <drvmgr/drvmgr_list.h>
0033 #include "drvmgr_internal.h"
0034 
0035 /* Unregister all children on a bus.
0036  *
0037  * This function is called from the bus driver, from a "safe" state where
0038  * devices will not be added or removed on this particular bus at this time
0039  */
0040 int drvmgr_children_unregister(struct drvmgr_bus *bus)
0041 {
0042     int err;
0043 
0044     while (bus->children != NULL) {
0045         err = drvmgr_dev_unregister(bus->children);
0046         if (err != DRVMGR_OK) {
0047             /* An error occurred */
0048             bus->children->error = err;
0049             return err;
0050         }
0051     }
0052 
0053     return DRVMGR_OK;
0054 }
0055 
0056 /* Unregister a BUS and all it's devices.
0057  *
0058  * It is up to the bus driver to remove all it's devices, either manually
0059  * one by one calling drvmgr_dev_unregister(), or by letting the driver
0060  * manager unregister all children by calling drvmgr_children_unregister().
0061  */
0062 int drvmgr_bus_unregister(struct drvmgr_bus *bus)
0063 {
0064     struct drvmgr *mgr = &drvmgr;
0065     struct drvmgr_list *list;
0066 
0067     if (bus->ops->remove == NULL)
0068         return DRVMGR_ENOSYS;
0069 
0070     /* Call Bus driver to clean things up, it must remove all children */
0071     bus->error = bus->ops->remove(bus);
0072     if (bus->error != DRVMGR_OK)
0073         return bus->error;
0074     /* Check that bus driver has done its job and removed all children */
0075     if (bus->children != NULL)
0076         return DRVMGR_FAIL;
0077     /* Remove References to bus */
0078     bus->dev->bus = NULL;
0079 
0080     DRVMGR_LOCK_WRITE();
0081 
0082     /* Remove bus from bus-list */
0083     if (bus->state & BUS_STATE_LIST_INACTIVE)
0084         list = &mgr->buses_inactive;
0085     else
0086         list = &mgr->buses[bus->level];
0087     drvmgr_list_remove(list, bus);
0088 
0089     DRVMGR_UNLOCK();
0090 
0091     /* All references to this bus has been removed at this point */
0092     free(bus);
0093 
0094     return DRVMGR_OK;
0095 }
0096 
0097 /* Separate Driver and Device from each other */
0098 int drvmgr_dev_drv_separate(struct drvmgr_dev *dev)
0099 {
0100     struct drvmgr *mgr = &drvmgr;
0101     struct drvmgr_dev *subdev, **pprev;
0102     int rc;
0103 
0104     /* Remove children if this device exports a bus of devices. All
0105      * children must be removed first as they depend upon the bus
0106      * services this bridge provide.
0107      */
0108     if (dev->bus) {
0109         rc = drvmgr_bus_unregister(dev->bus);
0110         if (rc != DRVMGR_OK)
0111             return rc;
0112     }
0113 
0114     if (dev->drv == NULL)
0115         return DRVMGR_OK;
0116 
0117     /* Remove device by letting assigned driver take care of hardware
0118      * issues
0119      */
0120     if (!dev->drv->ops->remove) {
0121         /* No remove function is considered severe when someone
0122          * is trying to remove the device
0123          */
0124         return DRVMGR_ENOSYS;
0125     }
0126     dev->error = dev->drv->ops->remove(dev);
0127     if (dev->error != DRVMGR_OK)
0128         return DRVMGR_FAIL;
0129 
0130     DRVMGR_LOCK_WRITE();
0131 
0132     /* Delete device from driver's device list */
0133     pprev = &dev->drv->dev;
0134     subdev = dev->drv->dev;
0135     while (subdev != dev) {
0136         pprev = &subdev->next_in_drv;
0137         subdev = subdev->next_in_drv;
0138     }
0139     *pprev = subdev->next_in_drv;
0140     dev->drv->dev_cnt--;
0141 
0142     /* Move device to inactive list */
0143     drvmgr_list_remove(&mgr->devices[dev->level], dev);
0144     dev->level = 0;
0145     dev->state &= ~(DEV_STATE_UNITED|DEV_STATE_INIT_DONE);
0146     dev->state |= DEV_STATE_LIST_INACTIVE;
0147     drvmgr_list_add_tail(&mgr->devices_inactive, dev);
0148 
0149     DRVMGR_UNLOCK();
0150 
0151     /* Free Device Driver Private memory if allocated previously by
0152      * Driver manager.
0153      */
0154     if (dev->drv->dev_priv_size && dev->priv) {
0155         free(dev->priv);
0156         dev->priv = NULL;
0157     }
0158     dev->drv = NULL;
0159 
0160     return DRVMGR_OK;
0161 }
0162 
0163 /* Unregister device,
0164  *  - let assigned driver handle deletion
0165  *  - remove from device list
0166  *  - remove from driver list
0167  *  - remove from bus list
0168  */
0169 int drvmgr_dev_unregister(struct drvmgr_dev *dev)
0170 {
0171     struct drvmgr *mgr = &drvmgr;
0172     struct drvmgr_dev *subdev, **pprev;
0173     int err;
0174 
0175     /* Separate device from driver, if the device is united with a driver.
0176      *
0177      * If this device is a bridge all child buses/devices are also removed.
0178      */
0179     err = drvmgr_dev_drv_separate(dev);
0180     if (err != DRVMGR_OK)
0181         return err;
0182 
0183     DRVMGR_LOCK_WRITE();
0184 
0185     /* Remove it from inactive list */
0186     drvmgr_list_remove(&mgr->devices_inactive, dev);
0187 
0188     /* Remove device from parent bus list (no check if dev not in list) */
0189     pprev = &dev->parent->children;
0190     subdev = dev->parent->children;
0191     while (subdev != dev) {
0192         pprev = &subdev->next_in_bus;
0193         subdev = subdev->next_in_bus;
0194     }
0195     *pprev = subdev->next_in_bus;
0196     dev->parent->dev_cnt--;
0197 
0198     DRVMGR_UNLOCK();
0199 
0200     /* All references to this device has been removed at this point */
0201     free(dev);
0202 
0203     return DRVMGR_OK;
0204 }