source: rtems/cpukit/libdrvmgr/drvmgr_unregister.c @ e7fade3

4.115
Last change on this file since e7fade3 was e7fade3, checked in by Daniel Hellstrom <daniel@…>, on 11/28/11 at 08:52:03

DRVMGR: added driver manager to cpukit/libdrvmgr

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