source: rtems/cpukit/libdrvmgr/drvmgr_unregister.c @ 7075fb11

Last change on this file since 7075fb11 was bb2f220, checked in by Daniel Hellstrom <daniel@…>, on Apr 13, 2015 at 8:49:47 AM

DRVMGR: renamed private drv_mgr and its struct name

  • Property mode set to 100644
File size: 4.5 KB
Line 
1/* Driver Manager Device Unregister (removal) implementation
2 *
3 * COPYRIGHT (c) 2011 Cobham Gaisler AB.
4 *
5 * The license and distribution terms for this file may be
6 * found in the file LICENSE in this distribution or at
7 * http://www.rtems.org/license/LICENSE.
8 */
9
10#include <stdlib.h>
11
12#include <drvmgr/drvmgr.h>
13#include <drvmgr/drvmgr_list.h>
14#include "drvmgr_internal.h"
15
16/* Unregister all children on a bus.
17 *
18 * This function is called from the bus driver, from a "safe" state where
19 * devices will not be added or removed on this particular bus at this time
20 */
21int drvmgr_children_unregister(struct drvmgr_bus *bus)
22{
23        int err;
24
25        while (bus->children != NULL) {
26                err = drvmgr_dev_unregister(bus->children);
27                if (err != DRVMGR_OK) {
28                        /* An error occured */
29                        bus->children->error = err;
30                        return err;
31                }
32        }
33
34        return DRVMGR_OK;
35}
36
37/* Unregister a BUS and all it's devices.
38 *
39 * It is up to the bus driver to remove all it's devices, either manually
40 * one by one calling drvmgr_dev_unregister(), or by letting the driver
41 * manager unregister all children by calling drvmgr_children_unregister().
42 */
43int drvmgr_bus_unregister(struct drvmgr_bus *bus)
44{
45        struct drvmgr *mgr = &drvmgr;
46        struct drvmgr_list *list;
47
48        if (bus->ops->remove == NULL)
49                return DRVMGR_ENOSYS;
50
51        /* Call Bus driver to clean things up, it must remove all children */
52        bus->error = bus->ops->remove(bus);
53        if (bus->error != DRVMGR_OK)
54                return bus->error;
55        /* Check that bus driver has done its job and removed all children */
56        if (bus->children != NULL)
57                return DRVMGR_FAIL;
58        /* Remove References to bus */
59        bus->dev->bus = NULL;
60
61        DRVMGR_LOCK_WRITE();
62
63        /* Remove bus from bus-list */
64        if (bus->state & BUS_STATE_LIST_INACTIVE)
65                list = &mgr->buses_inactive;
66        else
67                list = &mgr->buses[bus->level];
68        drvmgr_list_remove(list, bus);
69
70        DRVMGR_UNLOCK();
71
72        /* All references to this bus has been removed at this point */
73        free(bus);
74
75        return DRVMGR_OK;
76}
77
78/* Separate Driver and Device from each other */
79int drvmgr_dev_drv_separate(struct drvmgr_dev *dev)
80{
81        struct drvmgr *mgr = &drvmgr;
82        struct drvmgr_dev *subdev, **pprev;
83        int rc;
84
85        /* Remove children if this device exports a bus of devices. All
86         * children must be removed first as they depend upon the bus
87         * services this bridge provide.
88         */
89        if (dev->bus) {
90                rc = drvmgr_bus_unregister(dev->bus);
91                if (rc != DRVMGR_OK)
92                        return rc;
93        }
94
95        if (dev->drv == NULL)
96                return DRVMGR_OK;
97
98        /* Remove device by letting assigned driver take care of hardware
99         * issues
100         */
101        if (!dev->drv->ops->remove) {
102                /* No remove function is considered severe when someone
103                 * is trying to remove the device
104                 */
105                return DRVMGR_ENOSYS;
106        }
107        dev->error = dev->drv->ops->remove(dev);
108        if (dev->error != DRVMGR_OK)
109                return DRVMGR_FAIL;
110
111        DRVMGR_LOCK_WRITE();
112
113        /* Delete device from driver's device list */
114        pprev = &dev->drv->dev;
115        subdev = dev->drv->dev;
116        while (subdev != dev) {
117                pprev = &subdev->next_in_drv;
118                subdev = subdev->next_in_drv;
119        }
120        *pprev = subdev->next_in_drv;
121        dev->drv->dev_cnt--;
122
123        /* Move device to inactive list */
124        drvmgr_list_remove(&mgr->devices[dev->level], dev);
125        dev->level = 0;
126        dev->state &= ~(DEV_STATE_UNITED|DEV_STATE_INIT_DONE);
127        dev->state |= DEV_STATE_LIST_INACTIVE;
128        drvmgr_list_add_tail(&mgr->devices_inactive, dev);
129
130        DRVMGR_UNLOCK();
131
132        /* Free Device Driver Private memory if allocated previously by
133         * Driver manager.
134         */
135        if (dev->drv->dev_priv_size && dev->priv) {
136                free(dev->priv);
137                dev->priv = NULL;
138        }
139        dev->drv = NULL;
140
141        return DRVMGR_OK;
142}
143
144/* Unregister device,
145 *  - let assigned driver handle deletion
146 *  - remove from device list
147 *  - remove from driver list
148 *  - remove from bus list
149 */
150int drvmgr_dev_unregister(struct drvmgr_dev *dev)
151{
152        struct drvmgr *mgr = &drvmgr;
153        struct drvmgr_dev *subdev, **pprev;
154        int err;
155
156        /* Separate device from driver, if the device is united with a driver.
157         *
158         * If this device is a bridge all child buses/devices are also removed.
159         */
160        err = drvmgr_dev_drv_separate(dev);
161        if (err != DRVMGR_OK)
162                return err;
163
164        DRVMGR_LOCK_WRITE();
165
166        /* Remove it from inactive list */
167        drvmgr_list_remove(&mgr->devices_inactive, dev);
168
169        /* Remove device from parent bus list (no check if dev not in list) */
170        pprev = &dev->parent->children;
171        subdev = dev->parent->children;
172        while (subdev != dev) {
173                pprev = &subdev->next_in_bus;
174                subdev = subdev->next_in_bus;
175        }
176        *pprev = subdev->next_in_bus;
177        dev->parent->dev_cnt--;
178
179        DRVMGR_UNLOCK();
180
181        /* All references to this device has been removed at this point */
182        free(dev);
183
184        return DRVMGR_OK;
185}
Note: See TracBrowser for help on using the repository browser.