source: rtems/cpukit/libdrvmgr/drvmgr_unregister.c

Last change on this file was 72d83c61, checked in by Joel Sherrill <joel@…>, on 02/28/22 at 23:09:22

cpukit/libdrvmsg: Change license to BSD-2

Updates #3053.

  • Property mode set to 100644
File size: 5.6 KB
Line 
1/* SPDX-License-Identifier: BSD-2-Clause */
2
3/* Driver Manager Device Unregister (removal) implementation
4 *
5 * COPYRIGHT (c) 2011 Cobham Gaisler AB.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <stdlib.h>
30
31#include <drvmgr/drvmgr.h>
32#include <drvmgr/drvmgr_list.h>
33#include "drvmgr_internal.h"
34
35/* Unregister all children on a bus.
36 *
37 * This function is called from the bus driver, from a "safe" state where
38 * devices will not be added or removed on this particular bus at this time
39 */
40int drvmgr_children_unregister(struct drvmgr_bus *bus)
41{
42        int err;
43
44        while (bus->children != NULL) {
45                err = drvmgr_dev_unregister(bus->children);
46                if (err != DRVMGR_OK) {
47                        /* An error occurred */
48                        bus->children->error = err;
49                        return err;
50                }
51        }
52
53        return DRVMGR_OK;
54}
55
56/* Unregister a BUS and all it's devices.
57 *
58 * It is up to the bus driver to remove all it's devices, either manually
59 * one by one calling drvmgr_dev_unregister(), or by letting the driver
60 * manager unregister all children by calling drvmgr_children_unregister().
61 */
62int drvmgr_bus_unregister(struct drvmgr_bus *bus)
63{
64        struct drvmgr *mgr = &drvmgr;
65        struct drvmgr_list *list;
66
67        if (bus->ops->remove == NULL)
68                return DRVMGR_ENOSYS;
69
70        /* Call Bus driver to clean things up, it must remove all children */
71        bus->error = bus->ops->remove(bus);
72        if (bus->error != DRVMGR_OK)
73                return bus->error;
74        /* Check that bus driver has done its job and removed all children */
75        if (bus->children != NULL)
76                return DRVMGR_FAIL;
77        /* Remove References to bus */
78        bus->dev->bus = NULL;
79
80        DRVMGR_LOCK_WRITE();
81
82        /* Remove bus from bus-list */
83        if (bus->state & BUS_STATE_LIST_INACTIVE)
84                list = &mgr->buses_inactive;
85        else
86                list = &mgr->buses[bus->level];
87        drvmgr_list_remove(list, bus);
88
89        DRVMGR_UNLOCK();
90
91        /* All references to this bus has been removed at this point */
92        free(bus);
93
94        return DRVMGR_OK;
95}
96
97/* Separate Driver and Device from each other */
98int drvmgr_dev_drv_separate(struct drvmgr_dev *dev)
99{
100        struct drvmgr *mgr = &drvmgr;
101        struct drvmgr_dev *subdev, **pprev;
102        int rc;
103
104        /* Remove children if this device exports a bus of devices. All
105         * children must be removed first as they depend upon the bus
106         * services this bridge provide.
107         */
108        if (dev->bus) {
109                rc = drvmgr_bus_unregister(dev->bus);
110                if (rc != DRVMGR_OK)
111                        return rc;
112        }
113
114        if (dev->drv == NULL)
115                return DRVMGR_OK;
116
117        /* Remove device by letting assigned driver take care of hardware
118         * issues
119         */
120        if (!dev->drv->ops->remove) {
121                /* No remove function is considered severe when someone
122                 * is trying to remove the device
123                 */
124                return DRVMGR_ENOSYS;
125        }
126        dev->error = dev->drv->ops->remove(dev);
127        if (dev->error != DRVMGR_OK)
128                return DRVMGR_FAIL;
129
130        DRVMGR_LOCK_WRITE();
131
132        /* Delete device from driver's device list */
133        pprev = &dev->drv->dev;
134        subdev = dev->drv->dev;
135        while (subdev != dev) {
136                pprev = &subdev->next_in_drv;
137                subdev = subdev->next_in_drv;
138        }
139        *pprev = subdev->next_in_drv;
140        dev->drv->dev_cnt--;
141
142        /* Move device to inactive list */
143        drvmgr_list_remove(&mgr->devices[dev->level], dev);
144        dev->level = 0;
145        dev->state &= ~(DEV_STATE_UNITED|DEV_STATE_INIT_DONE);
146        dev->state |= DEV_STATE_LIST_INACTIVE;
147        drvmgr_list_add_tail(&mgr->devices_inactive, dev);
148
149        DRVMGR_UNLOCK();
150
151        /* Free Device Driver Private memory if allocated previously by
152         * Driver manager.
153         */
154        if (dev->drv->dev_priv_size && dev->priv) {
155                free(dev->priv);
156                dev->priv = NULL;
157        }
158        dev->drv = NULL;
159
160        return DRVMGR_OK;
161}
162
163/* Unregister device,
164 *  - let assigned driver handle deletion
165 *  - remove from device list
166 *  - remove from driver list
167 *  - remove from bus list
168 */
169int drvmgr_dev_unregister(struct drvmgr_dev *dev)
170{
171        struct drvmgr *mgr = &drvmgr;
172        struct drvmgr_dev *subdev, **pprev;
173        int err;
174
175        /* Separate device from driver, if the device is united with a driver.
176         *
177         * If this device is a bridge all child buses/devices are also removed.
178         */
179        err = drvmgr_dev_drv_separate(dev);
180        if (err != DRVMGR_OK)
181                return err;
182
183        DRVMGR_LOCK_WRITE();
184
185        /* Remove it from inactive list */
186        drvmgr_list_remove(&mgr->devices_inactive, dev);
187
188        /* Remove device from parent bus list (no check if dev not in list) */
189        pprev = &dev->parent->children;
190        subdev = dev->parent->children;
191        while (subdev != dev) {
192                pprev = &subdev->next_in_bus;
193                subdev = subdev->next_in_bus;
194        }
195        *pprev = subdev->next_in_bus;
196        dev->parent->dev_cnt--;
197
198        DRVMGR_UNLOCK();
199
200        /* All references to this device has been removed at this point */
201        free(dev);
202
203        return DRVMGR_OK;
204}
Note: See TracBrowser for help on using the repository browser.