xref: /third_party/FreeBSD/sys/kern/subr_bus.c (revision f9f848fa)
1f9f848faSopenharmony_ci/*-
2f9f848faSopenharmony_ci * SPDX-License-Identifier: BSD-2-Clause
3f9f848faSopenharmony_ci *
4f9f848faSopenharmony_ci * Copyright (c) 1997,1998,2003 Doug Rabson
5f9f848faSopenharmony_ci * All rights reserved.
6f9f848faSopenharmony_ci *
7f9f848faSopenharmony_ci * Redistribution and use in source and binary forms, with or without
8f9f848faSopenharmony_ci * modification, are permitted provided that the following conditions
9f9f848faSopenharmony_ci * are met:
10f9f848faSopenharmony_ci * 1. Redistributions of source code must retain the above copyright
11f9f848faSopenharmony_ci *    notice, this list of conditions and the following disclaimer.
12f9f848faSopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright
13f9f848faSopenharmony_ci *    notice, this list of conditions and the following disclaimer in the
14f9f848faSopenharmony_ci *    documentation and/or other materials provided with the distribution.
15f9f848faSopenharmony_ci *
16f9f848faSopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17f9f848faSopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18f9f848faSopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19f9f848faSopenharmony_ci * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20f9f848faSopenharmony_ci * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21f9f848faSopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22f9f848faSopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23f9f848faSopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24f9f848faSopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25f9f848faSopenharmony_ci * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26f9f848faSopenharmony_ci * SUCH DAMAGE.
27f9f848faSopenharmony_ci */
28f9f848faSopenharmony_ci
29f9f848faSopenharmony_ci#include <sys/cdefs.h>
30f9f848faSopenharmony_ci
31f9f848faSopenharmony_ci#include <sys/param.h>
32f9f848faSopenharmony_ci#include <sys/kobj.h>
33f9f848faSopenharmony_ci#include <sys/malloc.h>
34f9f848faSopenharmony_ci#include <sys/queue.h>
35f9f848faSopenharmony_ci#include <sys/systm.h>
36f9f848faSopenharmony_ci#include <sys/bus.h>
37f9f848faSopenharmony_ci#include <sys/mutex.h>
38f9f848faSopenharmony_ci#include "los_hwi.h"
39f9f848faSopenharmony_ci
40f9f848faSopenharmony_ci#ifndef BOOTVERBOSE
41f9f848faSopenharmony_ci#define BOOTVERBOSE     0
42f9f848faSopenharmony_ci#endif
43f9f848faSopenharmony_ciint     bootverbose = BOOTVERBOSE;
44f9f848faSopenharmony_ci
45f9f848faSopenharmony_ci/*
46f9f848faSopenharmony_ci *  * Used to attach drivers to devclasses.
47f9f848faSopenharmony_ci *   */
48f9f848faSopenharmony_citypedef struct driverlink *driverlink_t;
49f9f848faSopenharmony_cistruct driverlink {
50f9f848faSopenharmony_ci	kobj_class_t    driver;
51f9f848faSopenharmony_ci	TAILQ_ENTRY(driverlink) link;   /* list of drivers in devclass */
52f9f848faSopenharmony_ci	int             pass;
53f9f848faSopenharmony_ci	TAILQ_ENTRY(driverlink) passlink;
54f9f848faSopenharmony_ci};
55f9f848faSopenharmony_ci
56f9f848faSopenharmony_ci/*
57f9f848faSopenharmony_ci * Forward declarations
58f9f848faSopenharmony_ci */
59f9f848faSopenharmony_citypedef TAILQ_HEAD(devclass_list, devclass) devclass_list_t;
60f9f848faSopenharmony_citypedef TAILQ_HEAD(driver_list, driverlink) driver_list_t;
61f9f848faSopenharmony_citypedef TAILQ_HEAD(device_list, device) device_list_t;
62f9f848faSopenharmony_ci
63f9f848faSopenharmony_cistruct devclass {
64f9f848faSopenharmony_ci        TAILQ_ENTRY(devclass) link;
65f9f848faSopenharmony_ci        devclass_t      parent;         /* parent in devclass hierarchy */
66f9f848faSopenharmony_ci        driver_list_t   drivers;     /* bus devclasses store drivers for bus */
67f9f848faSopenharmony_ci        char            *name;
68f9f848faSopenharmony_ci        device_t        *devices;       /* array of devices indexed by unit */
69f9f848faSopenharmony_ci        int             maxunit;        /* size of devices array */
70f9f848faSopenharmony_ci        int             flags;
71f9f848faSopenharmony_ci#define DC_HAS_CHILDREN         1
72f9f848faSopenharmony_ci};
73f9f848faSopenharmony_ci
74f9f848faSopenharmony_ci/**
75f9f848faSopenharmony_ci * @brief Implementation of device.
76f9f848faSopenharmony_ci */
77f9f848faSopenharmony_cistruct device {
78f9f848faSopenharmony_ci        /*
79f9f848faSopenharmony_ci         * A device is a kernel object. The first field must be the
80f9f848faSopenharmony_ci         * current ops table for the object.
81f9f848faSopenharmony_ci         */
82f9f848faSopenharmony_ci        KOBJ_FIELDS;
83f9f848faSopenharmony_ci
84f9f848faSopenharmony_ci        /*
85f9f848faSopenharmony_ci         * Device hierarchy.
86f9f848faSopenharmony_ci         */
87f9f848faSopenharmony_ci        TAILQ_ENTRY(device)     link;   /**< list of devices in parent */
88f9f848faSopenharmony_ci        TAILQ_ENTRY(device)     devlink; /**< global device list membership */
89f9f848faSopenharmony_ci        device_t        parent;         /**< parent of this device  */
90f9f848faSopenharmony_ci        device_list_t   children;       /**< list of child devices */
91f9f848faSopenharmony_ci
92f9f848faSopenharmony_ci        /*
93f9f848faSopenharmony_ci         * Details of this device.
94f9f848faSopenharmony_ci         */
95f9f848faSopenharmony_ci        driver_t        *driver;        /**< current driver */
96f9f848faSopenharmony_ci        devclass_t      devclass;       /**< current device class */
97f9f848faSopenharmony_ci        int             unit;           /**< current unit number */
98f9f848faSopenharmony_ci        char*           nameunit;       /**< name+unit e.g. foodev0 */
99f9f848faSopenharmony_ci        char*           desc;           /**< driver specific description */
100f9f848faSopenharmony_ci        int             busy;           /**< count of calls to device_busy() */
101f9f848faSopenharmony_ci        device_state_t  state;          /**< current device state  */
102f9f848faSopenharmony_ci        uint32_t        devflags;       /**< api level flags for device_get_flags() */
103f9f848faSopenharmony_ci        u_int           flags;          /**< internal device flags  */
104f9f848faSopenharmony_ci        u_int   order;                  /**< order from device_add_child_ordered() */
105f9f848faSopenharmony_ci        void    *ivars;                 /**< instance variables  */
106f9f848faSopenharmony_ci        void    *softc;                 /**< current driver's variables  */
107f9f848faSopenharmony_ci};
108f9f848faSopenharmony_ci
109f9f848faSopenharmony_cistatic MALLOC_DEFINE(M_BUS, "bus", "Bus data structures");
110f9f848faSopenharmony_ci
111f9f848faSopenharmony_ci#ifdef BUS_DEBUG
112f9f848faSopenharmony_cistatic int bus_debug = 1;
113f9f848faSopenharmony_ci
114f9f848faSopenharmony_ci#define PDEBUG(a)       if (bus_debug) {PRINTK("%s:%d: ", __func__, __LINE__), PRINTK a; PRINTK("\n");}
115f9f848faSopenharmony_ci#define DEVICENAME(d)   ((d)? device_get_name(d): "no device")
116f9f848faSopenharmony_ci#define DRIVERNAME(d)   ((d)? d->name : "no driver")
117f9f848faSopenharmony_ci#define DEVCLANAME(d)   ((d)? d->name : "no devclass")
118f9f848faSopenharmony_ci
119f9f848faSopenharmony_ci/**
120f9f848faSopenharmony_ci * Produce the indenting, indent*2 spaces plus a '.' ahead of that to
121f9f848faSopenharmony_ci * prevent syslog from deleting initial spaces
122f9f848faSopenharmony_ci */
123f9f848faSopenharmony_ci#define indentprintf(p) do { int iJ; PRINTK("."); for (iJ=0; iJ<indent; iJ++) PRINTK("  "); PRINTK p ; } while (0)
124f9f848faSopenharmony_ci
125f9f848faSopenharmony_cistatic void print_device_short(device_t dev, int indent);
126f9f848faSopenharmony_cistatic void print_device(device_t dev, int indent);
127f9f848faSopenharmony_civoid print_device_tree_short(device_t dev, int indent);
128f9f848faSopenharmony_civoid print_device_tree(device_t dev, int indent);
129f9f848faSopenharmony_cistatic void print_driver_short(driver_t *driver, int indent);
130f9f848faSopenharmony_cistatic void print_driver(driver_t *driver, int indent);
131f9f848faSopenharmony_cistatic void print_driver_list(driver_list_t drivers, int indent);
132f9f848faSopenharmony_cistatic void print_devclass_short(devclass_t dc, int indent);
133f9f848faSopenharmony_cistatic void print_devclass(devclass_t dc, int indent);
134f9f848faSopenharmony_civoid print_devclass_list_short(void);
135f9f848faSopenharmony_civoid print_devclass_list(void);
136f9f848faSopenharmony_ci
137f9f848faSopenharmony_ci#else
138f9f848faSopenharmony_ci/* Make the compiler ignore the function calls */
139f9f848faSopenharmony_ci#define PDEBUG(a)                       /* nop */
140f9f848faSopenharmony_ci#define DEVICENAME(d)                   /* nop */
141f9f848faSopenharmony_ci#define DRIVERNAME(d)                   /* nop */
142f9f848faSopenharmony_ci#define DEVCLANAME(d)                   /* nop */
143f9f848faSopenharmony_ci
144f9f848faSopenharmony_ci#define print_device_short(d,i)         /* nop */
145f9f848faSopenharmony_ci#define print_device(d,i)               /* nop */
146f9f848faSopenharmony_ci#define print_device_tree_short(d,i)    /* nop */
147f9f848faSopenharmony_ci#define print_device_tree(d,i)          /* nop */
148f9f848faSopenharmony_ci#define print_driver_short(d,i)         /* nop */
149f9f848faSopenharmony_ci#define print_driver(d,i)               /* nop */
150f9f848faSopenharmony_ci#define print_driver_list(d,i)          /* nop */
151f9f848faSopenharmony_ci#define print_devclass_short(d,i)       /* nop */
152f9f848faSopenharmony_ci#define print_devclass(d,i)             /* nop */
153f9f848faSopenharmony_ci#define print_devclass_list_short()     /* nop */
154f9f848faSopenharmony_ci#define print_devclass_list()           /* nop */
155f9f848faSopenharmony_ci#endif
156f9f848faSopenharmony_ci
157f9f848faSopenharmony_cistatic TAILQ_HEAD(,device)      bus_data_devices;
158f9f848faSopenharmony_cistatic int bus_data_generation = 1;
159f9f848faSopenharmony_ci
160f9f848faSopenharmony_cistatic kobj_method_t null_methods[] = {
161f9f848faSopenharmony_ci        KOBJMETHOD_END
162f9f848faSopenharmony_ci};
163f9f848faSopenharmony_ci
164f9f848faSopenharmony_ciDEFINE_CLASS(null, null_methods, 0);
165f9f848faSopenharmony_ci
166f9f848faSopenharmony_ci/*
167f9f848faSopenharmony_ci * Bus pass implementation
168f9f848faSopenharmony_ci */
169f9f848faSopenharmony_ci
170f9f848faSopenharmony_cistatic driver_list_t passes = TAILQ_HEAD_INITIALIZER(passes);
171f9f848faSopenharmony_ciint bus_current_pass = BUS_PASS_ROOT;
172f9f848faSopenharmony_ci
173f9f848faSopenharmony_ci/**
174f9f848faSopenharmony_ci * @brief Return the name of the device's devclass or @c NULL if there
175f9f848faSopenharmony_ci * is none.
176f9f848faSopenharmony_ci */
177f9f848faSopenharmony_ciconst char *
178f9f848faSopenharmony_cidevice_get_name(device_t dev)
179f9f848faSopenharmony_ci{
180f9f848faSopenharmony_ci	if (dev != NULL && dev->devclass)
181f9f848faSopenharmony_ci		return (devclass_get_name(dev->devclass));
182f9f848faSopenharmony_ci	return (NULL);
183f9f848faSopenharmony_ci}
184f9f848faSopenharmony_ci
185f9f848faSopenharmony_ci/**
186f9f848faSopenharmony_ci * @internal
187f9f848faSopenharmony_ci * @brief Register the pass level of a new driver attachment
188f9f848faSopenharmony_ci *
189f9f848faSopenharmony_ci * Register a new driver attachment's pass level.  If no driver
190f9f848faSopenharmony_ci * attachment with the same pass level has been added, then @p new
191f9f848faSopenharmony_ci * will be added to the global passes list.
192f9f848faSopenharmony_ci *
193f9f848faSopenharmony_ci * @param new           the new driver attachment
194f9f848faSopenharmony_ci */
195f9f848faSopenharmony_cistatic void
196f9f848faSopenharmony_cidriver_register_pass(struct driverlink *new)
197f9f848faSopenharmony_ci{
198f9f848faSopenharmony_ci        struct driverlink *dl = NULL;
199f9f848faSopenharmony_ci
200f9f848faSopenharmony_ci        /* We only consider pass numbers during boot. */
201f9f848faSopenharmony_ci        if (bus_current_pass == BUS_PASS_DEFAULT)
202f9f848faSopenharmony_ci                return;
203f9f848faSopenharmony_ci
204f9f848faSopenharmony_ci        /*
205f9f848faSopenharmony_ci         * Walk the passes list.  If we already know about this pass
206f9f848faSopenharmony_ci         * then there is nothing to do.  If we don't, then insert this
207f9f848faSopenharmony_ci         * driver link into the list.
208f9f848faSopenharmony_ci         */
209f9f848faSopenharmony_ci        TAILQ_FOREACH(dl, &passes, passlink) {
210f9f848faSopenharmony_ci                if (dl->pass < new->pass)
211f9f848faSopenharmony_ci                        continue;
212f9f848faSopenharmony_ci                if (dl->pass == new->pass)
213f9f848faSopenharmony_ci                        return;
214f9f848faSopenharmony_ci                TAILQ_INSERT_BEFORE(dl, new, passlink);
215f9f848faSopenharmony_ci                return;
216f9f848faSopenharmony_ci        }
217f9f848faSopenharmony_ci        TAILQ_INSERT_TAIL(&passes, new, passlink);
218f9f848faSopenharmony_ci}
219f9f848faSopenharmony_ci
220f9f848faSopenharmony_ci/**
221f9f848faSopenharmony_ci * @brief Raise the current bus pass
222f9f848faSopenharmony_ci *
223f9f848faSopenharmony_ci * Raise the current bus pass level to @p pass.  Call the BUS_NEW_PASS()
224f9f848faSopenharmony_ci * method on the root bus to kick off a new device tree scan for each
225f9f848faSopenharmony_ci * new pass level that has at least one driver.
226f9f848faSopenharmony_ci */
227f9f848faSopenharmony_civoid
228f9f848faSopenharmony_cibus_set_pass(int pass)
229f9f848faSopenharmony_ci{
230f9f848faSopenharmony_ci        struct driverlink *dl = NULL;
231f9f848faSopenharmony_ci
232f9f848faSopenharmony_ci        if (bus_current_pass > pass)
233f9f848faSopenharmony_ci                panic("Attempt to lower bus pass level");
234f9f848faSopenharmony_ci
235f9f848faSopenharmony_ci        TAILQ_FOREACH(dl, &passes, passlink) {
236f9f848faSopenharmony_ci                /* Skip pass values below the current pass level. */
237f9f848faSopenharmony_ci                if (dl->pass <= bus_current_pass)
238f9f848faSopenharmony_ci                        continue;
239f9f848faSopenharmony_ci
240f9f848faSopenharmony_ci                /*
241f9f848faSopenharmony_ci                 * Bail once we hit a driver with a pass level that is
242f9f848faSopenharmony_ci                 * too high.
243f9f848faSopenharmony_ci                 */
244f9f848faSopenharmony_ci                if (dl->pass > pass)
245f9f848faSopenharmony_ci                        break;
246f9f848faSopenharmony_ci
247f9f848faSopenharmony_ci                /*
248f9f848faSopenharmony_ci                 * Raise the pass level to the next level and rescan
249f9f848faSopenharmony_ci                 * the tree.
250f9f848faSopenharmony_ci                 */
251f9f848faSopenharmony_ci                bus_current_pass = dl->pass;
252f9f848faSopenharmony_ci                BUS_NEW_PASS(root_bus);
253f9f848faSopenharmony_ci        }
254f9f848faSopenharmony_ci
255f9f848faSopenharmony_ci        /*
256f9f848faSopenharmony_ci         * If there isn't a driver registered for the requested pass,
257f9f848faSopenharmony_ci         * then bus_current_pass might still be less than 'pass'.  Set
258f9f848faSopenharmony_ci         * it to 'pass' in that case.
259f9f848faSopenharmony_ci         */
260f9f848faSopenharmony_ci        if (bus_current_pass < pass)
261f9f848faSopenharmony_ci                bus_current_pass = pass;
262f9f848faSopenharmony_ci        KASSERT(bus_current_pass == pass, ("Failed to update bus pass level"));
263f9f848faSopenharmony_ci}
264f9f848faSopenharmony_ci
265f9f848faSopenharmony_ci/*
266f9f848faSopenharmony_ci * Devclass implementation
267f9f848faSopenharmony_ci */
268f9f848faSopenharmony_ci
269f9f848faSopenharmony_cistatic devclass_list_t devclasses = TAILQ_HEAD_INITIALIZER(devclasses);
270f9f848faSopenharmony_ci
271f9f848faSopenharmony_ci/**
272f9f848faSopenharmony_ci * @internal
273f9f848faSopenharmony_ci * @brief Find or create a device class
274f9f848faSopenharmony_ci *
275f9f848faSopenharmony_ci * If a device class with the name @p classname exists, return it,
276f9f848faSopenharmony_ci * otherwise if @p create is non-zero create and return a new device
277f9f848faSopenharmony_ci * class.
278f9f848faSopenharmony_ci *
279f9f848faSopenharmony_ci * If @p parentname is non-NULL, the parent of the devclass is set to
280f9f848faSopenharmony_ci * the devclass of that name.
281f9f848faSopenharmony_ci *
282f9f848faSopenharmony_ci * @param classname     the devclass name to find or create
283f9f848faSopenharmony_ci * @param parentname    the parent devclass name or @c NULL
284f9f848faSopenharmony_ci * @param create        non-zero to create a devclass
285f9f848faSopenharmony_ci */
286f9f848faSopenharmony_cistatic devclass_t
287f9f848faSopenharmony_cidevclass_find_internal(const char *classname, const char *parentname,
288f9f848faSopenharmony_ci                       int create)
289f9f848faSopenharmony_ci{
290f9f848faSopenharmony_ci        devclass_t dc;
291f9f848faSopenharmony_ci
292f9f848faSopenharmony_ci        PDEBUG(("looking for %s", classname));
293f9f848faSopenharmony_ci        if (!classname)
294f9f848faSopenharmony_ci                return (NULL);
295f9f848faSopenharmony_ci
296f9f848faSopenharmony_ci        TAILQ_FOREACH(dc, &devclasses, link) {
297f9f848faSopenharmony_ci                if (!strcmp(dc->name, classname))
298f9f848faSopenharmony_ci                        break;
299f9f848faSopenharmony_ci        }
300f9f848faSopenharmony_ci
301f9f848faSopenharmony_ci        if (create && !dc) {
302f9f848faSopenharmony_ci                dc = bsd_malloc(sizeof(struct devclass) + strlen(classname) + 1,
303f9f848faSopenharmony_ci                    M_BUS, M_NOWAIT | M_ZERO);
304f9f848faSopenharmony_ci                if (!dc)
305f9f848faSopenharmony_ci                        return (NULL);
306f9f848faSopenharmony_ci                dc->parent = NULL;
307f9f848faSopenharmony_ci                dc->name = (char*) (dc + 1);
308f9f848faSopenharmony_ci                if (strcpy_s(dc->name, strlen(classname) + 1, classname) != EOK) {
309f9f848faSopenharmony_ci                        bsd_free(dc, M_BUS);
310f9f848faSopenharmony_ci                        return (NULL);
311f9f848faSopenharmony_ci                }
312f9f848faSopenharmony_ci                TAILQ_INIT(&dc->drivers);
313f9f848faSopenharmony_ci                TAILQ_INSERT_TAIL(&devclasses, dc, link);
314f9f848faSopenharmony_ci
315f9f848faSopenharmony_ci                PDEBUG(("create dc %p, %s", dc, classname));
316f9f848faSopenharmony_ci                bus_data_generation_update();
317f9f848faSopenharmony_ci        }
318f9f848faSopenharmony_ci
319f9f848faSopenharmony_ci        /*
320f9f848faSopenharmony_ci         * If a parent class is specified, then set that as our parent so
321f9f848faSopenharmony_ci         * that this devclass will support drivers for the parent class as
322f9f848faSopenharmony_ci         * well.  If the parent class has the same name don't do this though
323f9f848faSopenharmony_ci         * as it creates a cycle that can trigger an infinite loop in
324f9f848faSopenharmony_ci         * device_probe_child() if a device exists for which there is no
325f9f848faSopenharmony_ci         * suitable driver.
326f9f848faSopenharmony_ci         */
327f9f848faSopenharmony_ci        if (parentname && dc && !dc->parent &&
328f9f848faSopenharmony_ci            strcmp(classname, parentname) != 0) {
329f9f848faSopenharmony_ci                dc->parent = devclass_find_internal(parentname, NULL, TRUE);
330f9f848faSopenharmony_ci                if (dc->parent == NULL) {
331f9f848faSopenharmony_ci                    return (NULL);
332f9f848faSopenharmony_ci                }
333f9f848faSopenharmony_ci                dc->parent->flags = (unsigned int)dc->parent->flags | DC_HAS_CHILDREN;
334f9f848faSopenharmony_ci        }
335f9f848faSopenharmony_ci
336f9f848faSopenharmony_ci        PDEBUG(("found dc %p, %s", dc, classname));
337f9f848faSopenharmony_ci        return (dc);
338f9f848faSopenharmony_ci}
339f9f848faSopenharmony_ci
340f9f848faSopenharmony_ci/**
341f9f848faSopenharmony_ci * @brief Create a device class
342f9f848faSopenharmony_ci *
343f9f848faSopenharmony_ci * If a device class with the name @p classname exists, return it,
344f9f848faSopenharmony_ci * otherwise create and return a new device class.
345f9f848faSopenharmony_ci *
346f9f848faSopenharmony_ci * @param classname     the devclass name to find or create
347f9f848faSopenharmony_ci */
348f9f848faSopenharmony_cidevclass_t
349f9f848faSopenharmony_cidevclass_create(const char *classname)
350f9f848faSopenharmony_ci{
351f9f848faSopenharmony_ci        return (devclass_find_internal(classname, NULL, TRUE));
352f9f848faSopenharmony_ci}
353f9f848faSopenharmony_ci
354f9f848faSopenharmony_ci/**
355f9f848faSopenharmony_ci * @brief Find a device class
356f9f848faSopenharmony_ci *
357f9f848faSopenharmony_ci * If a device class with the name @p classname exists, return it,
358f9f848faSopenharmony_ci * otherwise return @c NULL.
359f9f848faSopenharmony_ci *
360f9f848faSopenharmony_ci * @param classname     the devclass name to find
361f9f848faSopenharmony_ci */
362f9f848faSopenharmony_cidevclass_t
363f9f848faSopenharmony_cidevclass_find(const char *classname)
364f9f848faSopenharmony_ci{
365f9f848faSopenharmony_ci        return (devclass_find_internal(classname, NULL, FALSE));
366f9f848faSopenharmony_ci}
367f9f848faSopenharmony_ci
368f9f848faSopenharmony_ci/**
369f9f848faSopenharmony_ci * @brief Register that a device driver has been added to a devclass
370f9f848faSopenharmony_ci *
371f9f848faSopenharmony_ci * Register that a device driver has been added to a devclass.  This
372f9f848faSopenharmony_ci * is called by devclass_add_driver to accomplish the recursive
373f9f848faSopenharmony_ci * notification of all the children classes of dc, as well as dc.
374f9f848faSopenharmony_ci * Each layer will have BUS_DRIVER_ADDED() called for all instances of
375f9f848faSopenharmony_ci * the devclass.
376f9f848faSopenharmony_ci *
377f9f848faSopenharmony_ci * We do a full search here of the devclass list at each iteration
378f9f848faSopenharmony_ci * level to save storing children-lists in the devclass structure.  If
379f9f848faSopenharmony_ci * we ever move beyond a few dozen devices doing this, we may need to
380f9f848faSopenharmony_ci * reevaluate...
381f9f848faSopenharmony_ci *
382f9f848faSopenharmony_ci * @param dc            the devclass to edit
383f9f848faSopenharmony_ci * @param driver        the driver that was just added
384f9f848faSopenharmony_ci */
385f9f848faSopenharmony_cistatic void
386f9f848faSopenharmony_cidevclass_driver_added(devclass_t dc, driver_t *driver)
387f9f848faSopenharmony_ci{
388f9f848faSopenharmony_ci        devclass_t parent;
389f9f848faSopenharmony_ci        int i;
390f9f848faSopenharmony_ci
391f9f848faSopenharmony_ci        /*
392f9f848faSopenharmony_ci         * Call BUS_DRIVER_ADDED for any existing busses in this class.
393f9f848faSopenharmony_ci         */
394f9f848faSopenharmony_ci        for (i = 0; i < dc->maxunit; i++)
395f9f848faSopenharmony_ci                if (dc->devices[i] && device_is_attached(dc->devices[i]))
396f9f848faSopenharmony_ci                        BUS_DRIVER_ADDED(dc->devices[i], driver);
397f9f848faSopenharmony_ci
398f9f848faSopenharmony_ci        /*
399f9f848faSopenharmony_ci         * Walk through the children classes.  Since we only keep a
400f9f848faSopenharmony_ci         * single parent pointer around, we walk the entire list of
401f9f848faSopenharmony_ci         * devclasses looking for children.  We set the
402f9f848faSopenharmony_ci         * DC_HAS_CHILDREN flag when a child devclass is created on
403f9f848faSopenharmony_ci         * the parent, so we only walk the list for those devclasses
404f9f848faSopenharmony_ci         * that have children.
405f9f848faSopenharmony_ci         */
406f9f848faSopenharmony_ci        if (!((unsigned int)dc->flags & DC_HAS_CHILDREN))
407f9f848faSopenharmony_ci                return;
408f9f848faSopenharmony_ci        parent = dc;
409f9f848faSopenharmony_ci        TAILQ_FOREACH(dc, &devclasses, link) {
410f9f848faSopenharmony_ci                if (dc->parent == parent)
411f9f848faSopenharmony_ci                        devclass_driver_added(dc, driver);
412f9f848faSopenharmony_ci        }
413f9f848faSopenharmony_ci}
414f9f848faSopenharmony_ci
415f9f848faSopenharmony_ci/**
416f9f848faSopenharmony_ci * @brief Add a device driver to a device class
417f9f848faSopenharmony_ci *
418f9f848faSopenharmony_ci * Add a device driver to a devclass. This is normally called
419f9f848faSopenharmony_ci * automatically by DRIVER_MODULE(). The BUS_DRIVER_ADDED() method of
420f9f848faSopenharmony_ci * all devices in the devclass will be called to allow them to attempt
421f9f848faSopenharmony_ci * to re-probe any unmatched children.
422f9f848faSopenharmony_ci *
423f9f848faSopenharmony_ci * @param dc            the devclass to edit
424f9f848faSopenharmony_ci * @param driver        the driver to register
425f9f848faSopenharmony_ci */
426f9f848faSopenharmony_ciint
427f9f848faSopenharmony_cidevclass_add_driver(devclass_t dc, driver_t *driver, int pass, devclass_t *dcp)
428f9f848faSopenharmony_ci{
429f9f848faSopenharmony_ci        driverlink_t dl = NULL;
430f9f848faSopenharmony_ci        const char *parentname = NULL;
431f9f848faSopenharmony_ci
432f9f848faSopenharmony_ci        PDEBUG(("%s +", DRIVERNAME(driver)));
433f9f848faSopenharmony_ci
434f9f848faSopenharmony_ci        /* Don't allow invalid pass values. */
435f9f848faSopenharmony_ci        if (pass <= BUS_PASS_ROOT)
436f9f848faSopenharmony_ci                return (EINVAL);
437f9f848faSopenharmony_ci
438f9f848faSopenharmony_ci        dl = bsd_malloc(sizeof *dl, M_BUS, M_NOWAIT|M_ZERO);
439f9f848faSopenharmony_ci        if (!dl)
440f9f848faSopenharmony_ci                return (ENOMEM);
441f9f848faSopenharmony_ci
442f9f848faSopenharmony_ci        /*
443f9f848faSopenharmony_ci         * Compile the driver's methods. Also increase the reference count
444f9f848faSopenharmony_ci         * so that the class doesn't get freed when the last instance
445f9f848faSopenharmony_ci         * goes. This means we can safely use static methods and avoids a
446f9f848faSopenharmony_ci         * double-free in devclass_delete_driver.
447f9f848faSopenharmony_ci         */
448f9f848faSopenharmony_ci        kobj_class_compile((kobj_class_t) driver);
449f9f848faSopenharmony_ci
450f9f848faSopenharmony_ci        /*
451f9f848faSopenharmony_ci         * If the driver has any base classes, make the
452f9f848faSopenharmony_ci         * devclass inherit from the devclass of the driver's
453f9f848faSopenharmony_ci         * first base class. This will allow the system to
454f9f848faSopenharmony_ci         * search for drivers in both devclasses for children
455f9f848faSopenharmony_ci         * of a device using this driver.
456f9f848faSopenharmony_ci         */
457f9f848faSopenharmony_ci        if (driver->baseclasses)
458f9f848faSopenharmony_ci                parentname = driver->baseclasses[0]->name;
459f9f848faSopenharmony_ci        else
460f9f848faSopenharmony_ci                parentname = NULL;
461f9f848faSopenharmony_ci        *dcp = devclass_find_internal(driver->name, parentname, TRUE);
462f9f848faSopenharmony_ci
463f9f848faSopenharmony_ci        dl->driver = driver;
464f9f848faSopenharmony_ci        TAILQ_INSERT_TAIL(&dc->drivers, dl, link);
465f9f848faSopenharmony_ci        driver->refs++;         /* XXX: kobj_mtx */
466f9f848faSopenharmony_ci        dl->pass = pass;
467f9f848faSopenharmony_ci        driver_register_pass(dl);
468f9f848faSopenharmony_ci
469f9f848faSopenharmony_ci        devclass_driver_added(dc, driver);
470f9f848faSopenharmony_ci        bus_data_generation_update();
471f9f848faSopenharmony_ci        PDEBUG(("%s -", DRIVERNAME(driver)));
472f9f848faSopenharmony_ci        return (0);
473f9f848faSopenharmony_ci}
474f9f848faSopenharmony_ci
475f9f848faSopenharmony_ci/**
476f9f848faSopenharmony_ci * @brief Register that a device driver has been deleted from a devclass
477f9f848faSopenharmony_ci *
478f9f848faSopenharmony_ci * Register that a device driver has been removed from a devclass.
479f9f848faSopenharmony_ci * This is called by devclass_delete_driver to accomplish the
480f9f848faSopenharmony_ci * recursive notification of all the children classes of busclass, as
481f9f848faSopenharmony_ci * well as busclass.  Each layer will attempt to detach the driver
482f9f848faSopenharmony_ci * from any devices that are children of the bus's devclass.  The function
483f9f848faSopenharmony_ci * will return an error if a device fails to detach.
484f9f848faSopenharmony_ci *
485f9f848faSopenharmony_ci * We do a full search here of the devclass list at each iteration
486f9f848faSopenharmony_ci * level to save storing children-lists in the devclass structure.  If
487f9f848faSopenharmony_ci * we ever move beyond a few dozen devices doing this, we may need to
488f9f848faSopenharmony_ci * reevaluate...
489f9f848faSopenharmony_ci *
490f9f848faSopenharmony_ci * @param busclass      the devclass of the parent bus
491f9f848faSopenharmony_ci * @param dc            the devclass of the driver being deleted
492f9f848faSopenharmony_ci * @param driver        the driver being deleted
493f9f848faSopenharmony_ci */
494f9f848faSopenharmony_cistatic int
495f9f848faSopenharmony_cidevclass_driver_deleted(devclass_t busclass, devclass_t dc, driver_t *driver)
496f9f848faSopenharmony_ci{
497f9f848faSopenharmony_ci        devclass_t parent;
498f9f848faSopenharmony_ci        device_t dev;
499f9f848faSopenharmony_ci        int error, i;
500f9f848faSopenharmony_ci
501f9f848faSopenharmony_ci        /*
502f9f848faSopenharmony_ci         * Disassociate from any devices.  We iterate through all the
503f9f848faSopenharmony_ci         * devices in the devclass of the driver and detach any which are
504f9f848faSopenharmony_ci         * using the driver and which have a parent in the devclass which
505f9f848faSopenharmony_ci         * we are deleting from.
506f9f848faSopenharmony_ci         *
507f9f848faSopenharmony_ci         * Note that since a driver can be in multiple devclasses, we
508f9f848faSopenharmony_ci         * should not detach devices which are not children of devices in
509f9f848faSopenharmony_ci         * the affected devclass.
510f9f848faSopenharmony_ci         */
511f9f848faSopenharmony_ci        for (i = 0; i < dc->maxunit; i++) {
512f9f848faSopenharmony_ci                if (dc->devices[i]) {
513f9f848faSopenharmony_ci                        dev = dc->devices[i];
514f9f848faSopenharmony_ci                        if (dev->driver == driver && dev->parent &&
515f9f848faSopenharmony_ci                            dev->parent->devclass == busclass) {
516f9f848faSopenharmony_ci                                if ((error = device_detach(dev)) != 0)
517f9f848faSopenharmony_ci                                        return (error);
518f9f848faSopenharmony_ci                                BUS_PROBE_NOMATCH(dev->parent, dev);
519f9f848faSopenharmony_ci                                // devnomatch(dev);
520f9f848faSopenharmony_ci                                dev->flags |= DF_DONENOMATCH;
521f9f848faSopenharmony_ci                        }
522f9f848faSopenharmony_ci                }
523f9f848faSopenharmony_ci        }
524f9f848faSopenharmony_ci
525f9f848faSopenharmony_ci        /*
526f9f848faSopenharmony_ci         * Walk through the children classes.  Since we only keep a
527f9f848faSopenharmony_ci         * single parent pointer around, we walk the entire list of
528f9f848faSopenharmony_ci         * devclasses looking for children.  We set the
529f9f848faSopenharmony_ci         * DC_HAS_CHILDREN flag when a child devclass is created on
530f9f848faSopenharmony_ci         * the parent, so we only walk the list for those devclasses
531f9f848faSopenharmony_ci         * that have children.
532f9f848faSopenharmony_ci         */
533f9f848faSopenharmony_ci        if (!((unsigned int)busclass->flags & DC_HAS_CHILDREN))
534f9f848faSopenharmony_ci                return (0);
535f9f848faSopenharmony_ci        parent = busclass;
536f9f848faSopenharmony_ci        TAILQ_FOREACH(busclass, &devclasses, link) {
537f9f848faSopenharmony_ci                if (busclass->parent == parent) {
538f9f848faSopenharmony_ci                        error = devclass_driver_deleted(busclass, dc, driver);
539f9f848faSopenharmony_ci                        if (error)
540f9f848faSopenharmony_ci                                return (error);
541f9f848faSopenharmony_ci                }
542f9f848faSopenharmony_ci        }
543f9f848faSopenharmony_ci        return (0);
544f9f848faSopenharmony_ci}
545f9f848faSopenharmony_ci
546f9f848faSopenharmony_ci/**
547f9f848faSopenharmony_ci * @brief Delete a device driver from a device class
548f9f848faSopenharmony_ci *
549f9f848faSopenharmony_ci * Delete a device driver from a devclass. This is normally called
550f9f848faSopenharmony_ci * automatically by DRIVER_MODULE().
551f9f848faSopenharmony_ci *
552f9f848faSopenharmony_ci * If the driver is currently attached to any devices,
553f9f848faSopenharmony_ci * devclass_delete_driver() will first attempt to detach from each
554f9f848faSopenharmony_ci * device. If one of the detach calls fails, the driver will not be
555f9f848faSopenharmony_ci * deleted.
556f9f848faSopenharmony_ci *
557f9f848faSopenharmony_ci * @param dc            the devclass to edit
558f9f848faSopenharmony_ci * @param driver        the driver to unregister
559f9f848faSopenharmony_ci */
560f9f848faSopenharmony_ciint
561f9f848faSopenharmony_cidevclass_delete_driver(devclass_t busclass, driver_t *driver)
562f9f848faSopenharmony_ci{
563f9f848faSopenharmony_ci        devclass_t dc = devclass_find(driver->name);
564f9f848faSopenharmony_ci        driverlink_t dl = NULL;
565f9f848faSopenharmony_ci        int error;
566f9f848faSopenharmony_ci
567f9f848faSopenharmony_ci        PDEBUG(("%s from devclass %s", driver->name, DEVCLANAME(busclass)));
568f9f848faSopenharmony_ci
569f9f848faSopenharmony_ci        if (!dc)
570f9f848faSopenharmony_ci                return (0);
571f9f848faSopenharmony_ci
572f9f848faSopenharmony_ci        /*
573f9f848faSopenharmony_ci         * Find the link structure in the bus' list of drivers.
574f9f848faSopenharmony_ci         */
575f9f848faSopenharmony_ci        TAILQ_FOREACH(dl, &busclass->drivers, link) {
576f9f848faSopenharmony_ci                if (dl->driver == driver)
577f9f848faSopenharmony_ci                        break;
578f9f848faSopenharmony_ci        }
579f9f848faSopenharmony_ci
580f9f848faSopenharmony_ci        if (!dl) {
581f9f848faSopenharmony_ci                PDEBUG(("%s not found in %s list", driver->name,
582f9f848faSopenharmony_ci                    busclass->name));
583f9f848faSopenharmony_ci                return (ENOENT);
584f9f848faSopenharmony_ci        }
585f9f848faSopenharmony_ci
586f9f848faSopenharmony_ci        error = devclass_driver_deleted(busclass, dc, driver);
587f9f848faSopenharmony_ci        if (error != 0)
588f9f848faSopenharmony_ci                return (error);
589f9f848faSopenharmony_ci
590f9f848faSopenharmony_ci        TAILQ_REMOVE(&busclass->drivers, dl, link);
591f9f848faSopenharmony_ci        bsd_free(dl, M_BUS);
592f9f848faSopenharmony_ci
593f9f848faSopenharmony_ci        /* XXX: kobj_mtx */
594f9f848faSopenharmony_ci        driver->refs--;
595f9f848faSopenharmony_ci        if (driver->refs == 0)
596f9f848faSopenharmony_ci                kobj_class_free((kobj_class_t) driver);
597f9f848faSopenharmony_ci
598f9f848faSopenharmony_ci        bus_data_generation_update();
599f9f848faSopenharmony_ci        return (0);
600f9f848faSopenharmony_ci}
601f9f848faSopenharmony_ci
602f9f848faSopenharmony_ci/**
603f9f848faSopenharmony_ci * @brief Quiesces a set of device drivers from a device class
604f9f848faSopenharmony_ci *
605f9f848faSopenharmony_ci * Quiesce a device driver from a devclass. This is normally called
606f9f848faSopenharmony_ci * automatically by DRIVER_MODULE().
607f9f848faSopenharmony_ci *
608f9f848faSopenharmony_ci * If the driver is currently attached to any devices,
609f9f848faSopenharmony_ci * devclass_quiesece_driver() will first attempt to quiesce each
610f9f848faSopenharmony_ci * device.
611f9f848faSopenharmony_ci *
612f9f848faSopenharmony_ci * @param dc            the devclass to edit
613f9f848faSopenharmony_ci * @param driver        the driver to unregister
614f9f848faSopenharmony_ci */
615f9f848faSopenharmony_cistatic int
616f9f848faSopenharmony_cidevclass_quiesce_driver(devclass_t busclass, driver_t *driver)
617f9f848faSopenharmony_ci{
618f9f848faSopenharmony_ci        devclass_t dc = devclass_find(driver->name);
619f9f848faSopenharmony_ci        driverlink_t dl = NULL;
620f9f848faSopenharmony_ci        device_t dev;
621f9f848faSopenharmony_ci        int i;
622f9f848faSopenharmony_ci        int error;
623f9f848faSopenharmony_ci
624f9f848faSopenharmony_ci        PDEBUG(("%s from devclass %s", driver->name, DEVCLANAME(busclass)));
625f9f848faSopenharmony_ci
626f9f848faSopenharmony_ci        if (!dc)
627f9f848faSopenharmony_ci                return (0);
628f9f848faSopenharmony_ci
629f9f848faSopenharmony_ci        /*
630f9f848faSopenharmony_ci         * Find the link structure in the bus' list of drivers.
631f9f848faSopenharmony_ci         */
632f9f848faSopenharmony_ci        TAILQ_FOREACH(dl, &busclass->drivers, link) {
633f9f848faSopenharmony_ci                if (dl->driver == driver)
634f9f848faSopenharmony_ci                        break;
635f9f848faSopenharmony_ci        }
636f9f848faSopenharmony_ci
637f9f848faSopenharmony_ci        if (!dl) {
638f9f848faSopenharmony_ci                PDEBUG(("%s not found in %s list", driver->name,
639f9f848faSopenharmony_ci                    busclass->name));
640f9f848faSopenharmony_ci                return (ENOENT);
641f9f848faSopenharmony_ci        }
642f9f848faSopenharmony_ci
643f9f848faSopenharmony_ci        /*
644f9f848faSopenharmony_ci         * Quiesce all devices.  We iterate through all the devices in
645f9f848faSopenharmony_ci         * the devclass of the driver and quiesce any which are using
646f9f848faSopenharmony_ci         * the driver and which have a parent in the devclass which we
647f9f848faSopenharmony_ci         * are quiescing.
648f9f848faSopenharmony_ci         *
649f9f848faSopenharmony_ci         * Note that since a driver can be in multiple devclasses, we
650f9f848faSopenharmony_ci         * should not quiesce devices which are not children of
651f9f848faSopenharmony_ci         * devices in the affected devclass.
652f9f848faSopenharmony_ci         */
653f9f848faSopenharmony_ci        for (i = 0; i < dc->maxunit; i++) {
654f9f848faSopenharmony_ci                if (dc->devices[i]) {
655f9f848faSopenharmony_ci                        dev = dc->devices[i];
656f9f848faSopenharmony_ci                        if (dev->driver == driver && dev->parent &&
657f9f848faSopenharmony_ci                            dev->parent->devclass == busclass) {
658f9f848faSopenharmony_ci                                if ((error = device_quiesce(dev)) != 0)
659f9f848faSopenharmony_ci                                        return (error);
660f9f848faSopenharmony_ci                        }
661f9f848faSopenharmony_ci                }
662f9f848faSopenharmony_ci        }
663f9f848faSopenharmony_ci
664f9f848faSopenharmony_ci        return (0);
665f9f848faSopenharmony_ci}
666f9f848faSopenharmony_ci
667f9f848faSopenharmony_ci/**
668f9f848faSopenharmony_ci * @internal
669f9f848faSopenharmony_ci */
670f9f848faSopenharmony_cistatic driverlink_t
671f9f848faSopenharmony_cidevclass_find_driver_internal(devclass_t dc, const char *classname)
672f9f848faSopenharmony_ci{
673f9f848faSopenharmony_ci        driverlink_t dl = NULL;
674f9f848faSopenharmony_ci
675f9f848faSopenharmony_ci        PDEBUG(("%s in devclass %s", classname, DEVCLANAME(dc)));
676f9f848faSopenharmony_ci
677f9f848faSopenharmony_ci        TAILQ_FOREACH(dl, &dc->drivers, link) {
678f9f848faSopenharmony_ci                if (!strcmp(dl->driver->name, classname))
679f9f848faSopenharmony_ci                        return (dl);
680f9f848faSopenharmony_ci        }
681f9f848faSopenharmony_ci
682f9f848faSopenharmony_ci        PDEBUG(("not found"));
683f9f848faSopenharmony_ci        return (NULL);
684f9f848faSopenharmony_ci}
685f9f848faSopenharmony_ci
686f9f848faSopenharmony_ci/**
687f9f848faSopenharmony_ci * @brief Return the name of the devclass
688f9f848faSopenharmony_ci */
689f9f848faSopenharmony_ciconst char *
690f9f848faSopenharmony_cidevclass_get_name(devclass_t dc)
691f9f848faSopenharmony_ci{
692f9f848faSopenharmony_ci        return (dc->name);
693f9f848faSopenharmony_ci}
694f9f848faSopenharmony_ci
695f9f848faSopenharmony_ci/**
696f9f848faSopenharmony_ci * @brief Find a device given a unit number
697f9f848faSopenharmony_ci *
698f9f848faSopenharmony_ci * @param dc            the devclass to search
699f9f848faSopenharmony_ci * @param unit          the unit number to search for
700f9f848faSopenharmony_ci *
701f9f848faSopenharmony_ci * @returns             the device with the given unit number or @c
702f9f848faSopenharmony_ci *                      NULL if there is no such device
703f9f848faSopenharmony_ci */
704f9f848faSopenharmony_cidevice_t
705f9f848faSopenharmony_cidevclass_get_device(devclass_t dc, int unit)
706f9f848faSopenharmony_ci{
707f9f848faSopenharmony_ci        if (dc == NULL || unit < 0 || unit >= dc->maxunit)
708f9f848faSopenharmony_ci                return (NULL);
709f9f848faSopenharmony_ci        return (dc->devices[unit]);
710f9f848faSopenharmony_ci}
711f9f848faSopenharmony_ci
712f9f848faSopenharmony_ci/**
713f9f848faSopenharmony_ci * @brief Find the softc field of a device given a unit number
714f9f848faSopenharmony_ci *
715f9f848faSopenharmony_ci * @param dc            the devclass to search
716f9f848faSopenharmony_ci * @param unit          the unit number to search for
717f9f848faSopenharmony_ci *
718f9f848faSopenharmony_ci * @returns             the softc field of the device with the given
719f9f848faSopenharmony_ci *                      unit number or @c NULL if there is no such
720f9f848faSopenharmony_ci *                      device
721f9f848faSopenharmony_ci */
722f9f848faSopenharmony_civoid *
723f9f848faSopenharmony_cidevclass_get_softc(devclass_t dc, int unit)
724f9f848faSopenharmony_ci{
725f9f848faSopenharmony_ci        device_t dev;
726f9f848faSopenharmony_ci
727f9f848faSopenharmony_ci        dev = devclass_get_device(dc, unit);
728f9f848faSopenharmony_ci        if (!dev)
729f9f848faSopenharmony_ci                return (NULL);
730f9f848faSopenharmony_ci
731f9f848faSopenharmony_ci        return (device_get_softc(dev));
732f9f848faSopenharmony_ci}
733f9f848faSopenharmony_ci
734f9f848faSopenharmony_ci/**
735f9f848faSopenharmony_ci * @brief Get a list of devices in the devclass
736f9f848faSopenharmony_ci *
737f9f848faSopenharmony_ci * An array containing a list of all the devices in the given devclass
738f9f848faSopenharmony_ci * is allocated and returned in @p *devlistp. The number of devices
739f9f848faSopenharmony_ci * in the array is returned in @p *devcountp. The caller should free
740f9f848faSopenharmony_ci * the array using @c free(p, M_TEMP), even if @p *devcountp is 0.
741f9f848faSopenharmony_ci *
742f9f848faSopenharmony_ci * @param dc            the devclass to examine
743f9f848faSopenharmony_ci * @param devlistp      points at location for array pointer return
744f9f848faSopenharmony_ci *                      value
745f9f848faSopenharmony_ci * @param devcountp     points at location for array size return value
746f9f848faSopenharmony_ci *
747f9f848faSopenharmony_ci * @retval 0            success
748f9f848faSopenharmony_ci * @retval ENOMEM       the array allocation failed
749f9f848faSopenharmony_ci */
750f9f848faSopenharmony_ciint
751f9f848faSopenharmony_cidevclass_get_devices(devclass_t dc, device_t **devlistp, int *devcountp)
752f9f848faSopenharmony_ci{
753f9f848faSopenharmony_ci        int count, i;
754f9f848faSopenharmony_ci        device_t *list;
755f9f848faSopenharmony_ci
756f9f848faSopenharmony_ci        count = devclass_get_count(dc);
757f9f848faSopenharmony_ci        list = bsd_malloc(count * sizeof(device_t), M_TEMP, M_NOWAIT|M_ZERO);
758f9f848faSopenharmony_ci        if (!list)
759f9f848faSopenharmony_ci                return (ENOMEM);
760f9f848faSopenharmony_ci
761f9f848faSopenharmony_ci        count = 0;
762f9f848faSopenharmony_ci        for (i = 0; i < dc->maxunit; i++) {
763f9f848faSopenharmony_ci                if (dc->devices[i]) {
764f9f848faSopenharmony_ci                        list[count] = dc->devices[i];
765f9f848faSopenharmony_ci                        count++;
766f9f848faSopenharmony_ci                }
767f9f848faSopenharmony_ci        }
768f9f848faSopenharmony_ci
769f9f848faSopenharmony_ci        *devlistp = list;
770f9f848faSopenharmony_ci        *devcountp = count;
771f9f848faSopenharmony_ci
772f9f848faSopenharmony_ci        return (0);
773f9f848faSopenharmony_ci}
774f9f848faSopenharmony_ci
775f9f848faSopenharmony_ci/**
776f9f848faSopenharmony_ci * @brief Get a list of drivers in the devclass
777f9f848faSopenharmony_ci *
778f9f848faSopenharmony_ci * An array containing a list of pointers to all the drivers in the
779f9f848faSopenharmony_ci * given devclass is allocated and returned in @p *listp.  The number
780f9f848faSopenharmony_ci * of drivers in the array is returned in @p *countp. The caller should
781f9f848faSopenharmony_ci * free the array using @c free(p, M_TEMP).
782f9f848faSopenharmony_ci *
783f9f848faSopenharmony_ci * @param dc            the devclass to examine
784f9f848faSopenharmony_ci * @param listp         gives location for array pointer return value
785f9f848faSopenharmony_ci * @param countp        gives location for number of array elements
786f9f848faSopenharmony_ci *                      return value
787f9f848faSopenharmony_ci *
788f9f848faSopenharmony_ci * @retval 0            success
789f9f848faSopenharmony_ci * @retval ENOMEM       the array allocation failed
790f9f848faSopenharmony_ci */
791f9f848faSopenharmony_ciint
792f9f848faSopenharmony_cidevclass_get_drivers(devclass_t dc, driver_t ***listp, int *countp)
793f9f848faSopenharmony_ci{
794f9f848faSopenharmony_ci        driverlink_t dl = NULL;
795f9f848faSopenharmony_ci        driver_t **list = NULL;
796f9f848faSopenharmony_ci        int count;
797f9f848faSopenharmony_ci
798f9f848faSopenharmony_ci        count = 0;
799f9f848faSopenharmony_ci        TAILQ_FOREACH(dl, &dc->drivers, link)
800f9f848faSopenharmony_ci                count++;
801f9f848faSopenharmony_ci        list = bsd_malloc(count * sizeof(driver_t *), M_TEMP, M_NOWAIT);
802f9f848faSopenharmony_ci        if (list == NULL)
803f9f848faSopenharmony_ci                return (ENOMEM);
804f9f848faSopenharmony_ci
805f9f848faSopenharmony_ci        count = 0;
806f9f848faSopenharmony_ci        TAILQ_FOREACH(dl, &dc->drivers, link) {
807f9f848faSopenharmony_ci                list[count] = dl->driver;
808f9f848faSopenharmony_ci                count++;
809f9f848faSopenharmony_ci        }
810f9f848faSopenharmony_ci        *listp = list;
811f9f848faSopenharmony_ci        *countp = count;
812f9f848faSopenharmony_ci
813f9f848faSopenharmony_ci        return (0);
814f9f848faSopenharmony_ci}
815f9f848faSopenharmony_ci
816f9f848faSopenharmony_ci/**
817f9f848faSopenharmony_ci * @brief Get the number of devices in a devclass
818f9f848faSopenharmony_ci *
819f9f848faSopenharmony_ci * @param dc            the devclass to examine
820f9f848faSopenharmony_ci */
821f9f848faSopenharmony_ciint
822f9f848faSopenharmony_cidevclass_get_count(devclass_t dc)
823f9f848faSopenharmony_ci{
824f9f848faSopenharmony_ci        int count, i;
825f9f848faSopenharmony_ci
826f9f848faSopenharmony_ci        count = 0;
827f9f848faSopenharmony_ci        for (i = 0; i < dc->maxunit; i++)
828f9f848faSopenharmony_ci                if (dc->devices[i])
829f9f848faSopenharmony_ci                        count++;
830f9f848faSopenharmony_ci        return (count);
831f9f848faSopenharmony_ci}
832f9f848faSopenharmony_ci
833f9f848faSopenharmony_ci/**
834f9f848faSopenharmony_ci * @brief Get the maximum unit number used in a devclass
835f9f848faSopenharmony_ci *
836f9f848faSopenharmony_ci * Note that this is one greater than the highest currently-allocated
837f9f848faSopenharmony_ci * unit.  If a null devclass_t is passed in, -1 is returned to indicate
838f9f848faSopenharmony_ci * that not even the devclass has been allocated yet.
839f9f848faSopenharmony_ci *
840f9f848faSopenharmony_ci * @param dc            the devclass to examine
841f9f848faSopenharmony_ci */
842f9f848faSopenharmony_ciint
843f9f848faSopenharmony_cidevclass_get_maxunit(devclass_t dc)
844f9f848faSopenharmony_ci{
845f9f848faSopenharmony_ci        if (dc == NULL)
846f9f848faSopenharmony_ci                return (-1);
847f9f848faSopenharmony_ci        return (dc->maxunit);
848f9f848faSopenharmony_ci}
849f9f848faSopenharmony_ci
850f9f848faSopenharmony_ci/**
851f9f848faSopenharmony_ci * @brief Find a free unit number in a devclass
852f9f848faSopenharmony_ci *
853f9f848faSopenharmony_ci * This function searches for the first unused unit number greater
854f9f848faSopenharmony_ci * that or equal to @p unit.
855f9f848faSopenharmony_ci *
856f9f848faSopenharmony_ci * @param dc            the devclass to examine
857f9f848faSopenharmony_ci * @param unit          the first unit number to check
858f9f848faSopenharmony_ci */
859f9f848faSopenharmony_ciint
860f9f848faSopenharmony_cidevclass_find_free_unit(devclass_t dc, int unit)
861f9f848faSopenharmony_ci{
862f9f848faSopenharmony_ci        if (dc == NULL)
863f9f848faSopenharmony_ci                return (unit);
864f9f848faSopenharmony_ci        while (unit < dc->maxunit && dc->devices[unit] != NULL)
865f9f848faSopenharmony_ci                unit++;
866f9f848faSopenharmony_ci        return (unit);
867f9f848faSopenharmony_ci}
868f9f848faSopenharmony_ci
869f9f848faSopenharmony_ci/**
870f9f848faSopenharmony_ci * @brief Set the parent of a devclass
871f9f848faSopenharmony_ci *
872f9f848faSopenharmony_ci * The parent class is normally initialised automatically by
873f9f848faSopenharmony_ci * DRIVER_MODULE().
874f9f848faSopenharmony_ci *
875f9f848faSopenharmony_ci * @param dc            the devclass to edit
876f9f848faSopenharmony_ci * @param pdc           the new parent devclass
877f9f848faSopenharmony_ci */
878f9f848faSopenharmony_civoid
879f9f848faSopenharmony_cidevclass_set_parent(devclass_t dc, devclass_t pdc)
880f9f848faSopenharmony_ci{
881f9f848faSopenharmony_ci        dc->parent = pdc;
882f9f848faSopenharmony_ci}
883f9f848faSopenharmony_ci
884f9f848faSopenharmony_ci/**
885f9f848faSopenharmony_ci * @brief Get the parent of a devclass
886f9f848faSopenharmony_ci *
887f9f848faSopenharmony_ci * @param dc            the devclass to examine
888f9f848faSopenharmony_ci */
889f9f848faSopenharmony_cidevclass_t
890f9f848faSopenharmony_cidevclass_get_parent(devclass_t dc)
891f9f848faSopenharmony_ci{
892f9f848faSopenharmony_ci        return (dc->parent);
893f9f848faSopenharmony_ci}
894f9f848faSopenharmony_ci
895f9f848faSopenharmony_ci/**
896f9f848faSopenharmony_ci * @internal
897f9f848faSopenharmony_ci * @brief Allocate a unit number
898f9f848faSopenharmony_ci *
899f9f848faSopenharmony_ci * On entry, @p *unitp is the desired unit number (or @c -1 if any
900f9f848faSopenharmony_ci * will do). The allocated unit number is returned in @p *unitp.
901f9f848faSopenharmony_ci
902f9f848faSopenharmony_ci * @param dc            the devclass to allocate from
903f9f848faSopenharmony_ci * @param unitp         points at the location for the allocated unit
904f9f848faSopenharmony_ci *                      number
905f9f848faSopenharmony_ci *
906f9f848faSopenharmony_ci * @retval 0            success
907f9f848faSopenharmony_ci * @retval EEXIST       the requested unit number is already allocated
908f9f848faSopenharmony_ci * @retval ENOMEM       memory allocation failure
909f9f848faSopenharmony_ci */
910f9f848faSopenharmony_cistatic int
911f9f848faSopenharmony_cidevclass_alloc_unit(devclass_t dc, device_t dev, int *unitp)
912f9f848faSopenharmony_ci{
913f9f848faSopenharmony_ci    int unit = *unitp;
914f9f848faSopenharmony_ci
915f9f848faSopenharmony_ci    PDEBUG(("unit %d in devclass %s", unit, DEVCLANAME(dc)));
916f9f848faSopenharmony_ci
917f9f848faSopenharmony_ci    /* Ask the parent bus if it wants to wire this device. */
918f9f848faSopenharmony_ci    if (unit == -1)
919f9f848faSopenharmony_ci        BUS_HINT_DEVICE_UNIT(device_get_parent(dev), dev, dc->name, &unit);
920f9f848faSopenharmony_ci
921f9f848faSopenharmony_ci    /* If we were given a wired unit number, check for existing device */
922f9f848faSopenharmony_ci    /* XXX imp XXX */
923f9f848faSopenharmony_ci    if (unit != -1) {
924f9f848faSopenharmony_ci        if (unit >= 0 && unit < dc->maxunit && dc->devices[unit] != NULL) {
925f9f848faSopenharmony_ci            if (bootverbose)
926f9f848faSopenharmony_ci                printf("%s: %s%d already exists; skipping it\n", dc->name, dc->name, *unitp);
927f9f848faSopenharmony_ci            return (EEXIST);
928f9f848faSopenharmony_ci        }
929f9f848faSopenharmony_ci    } else {
930f9f848faSopenharmony_ci        /* Unwired device, find the next available slot for it */
931f9f848faSopenharmony_ci        unit = 0;
932f9f848faSopenharmony_ci        for (unit = 0;; unit++) {
933f9f848faSopenharmony_ci            /* If this device slot is already in use, skip it. */
934f9f848faSopenharmony_ci            if (unit < dc->maxunit && dc->devices[unit] != NULL)
935f9f848faSopenharmony_ci                continue;
936f9f848faSopenharmony_ci
937f9f848faSopenharmony_ci            break;
938f9f848faSopenharmony_ci        }
939f9f848faSopenharmony_ci    }
940f9f848faSopenharmony_ci    PDEBUG(("mid: unit %d in devclass %s", unit, DEVCLANAME(dc)));
941f9f848faSopenharmony_ci    /*
942f9f848faSopenharmony_ci     * We've selected a unit beyond the length of the table, so let's
943f9f848faSopenharmony_ci     * extend the table to make room for all units up to and including
944f9f848faSopenharmony_ci     * this one.
945f9f848faSopenharmony_ci     */
946f9f848faSopenharmony_ci    if (unit >= dc->maxunit) {
947f9f848faSopenharmony_ci        device_t *newlist, *oldlist;
948f9f848faSopenharmony_ci        int newsize;
949f9f848faSopenharmony_ci
950f9f848faSopenharmony_ci        oldlist = dc->devices;
951f9f848faSopenharmony_ci        newsize = roundup((unit + 1), MINALLOCSIZE / sizeof(device_t));
952f9f848faSopenharmony_ci        newlist = bsd_malloc(sizeof(device_t) * newsize, M_BUS, M_NOWAIT);
953f9f848faSopenharmony_ci		PDEBUG(("oldlist %p, newlist %p, newsize %d", oldlist, newlist, newsize));
954f9f848faSopenharmony_ci        if (!newlist)
955f9f848faSopenharmony_ci            return (ENOMEM);
956f9f848faSopenharmony_ci		PDEBUG(("start memcpy, size %d", sizeof(device_t) * dc->maxunit));
957f9f848faSopenharmony_ci        if (oldlist != NULL)
958f9f848faSopenharmony_ci            (void)memcpy_s(newlist, sizeof(device_t) * dc->maxunit, oldlist, sizeof(device_t) * dc->maxunit);
959f9f848faSopenharmony_ci        PDEBUG(("start memset, maxunit %d, size %d", dc->maxunit, sizeof(device_t) * (newsize - dc->maxunit)));
960f9f848faSopenharmony_ci        (void)memset_s(newlist + dc->maxunit, sizeof(device_t) * (newsize - dc->maxunit), 0,
961f9f848faSopenharmony_ci                       sizeof(device_t) * (newsize - dc->maxunit));
962f9f848faSopenharmony_ci        dc->devices = newlist;
963f9f848faSopenharmony_ci        dc->maxunit = newsize;
964f9f848faSopenharmony_ci        if (oldlist != NULL)
965f9f848faSopenharmony_ci            bsd_free(oldlist, M_BUS);
966f9f848faSopenharmony_ci    }
967f9f848faSopenharmony_ci    PDEBUG(("now: unit %d in devclass %s", unit, DEVCLANAME(dc)));
968f9f848faSopenharmony_ci
969f9f848faSopenharmony_ci    *unitp = unit;
970f9f848faSopenharmony_ci    return (0);
971f9f848faSopenharmony_ci}
972f9f848faSopenharmony_ci
973f9f848faSopenharmony_ci/**
974f9f848faSopenharmony_ci * @internal
975f9f848faSopenharmony_ci */
976f9f848faSopenharmony_cistatic void
977f9f848faSopenharmony_cidevice_set_desc_internal(device_t dev, const char* desc, int copy)
978f9f848faSopenharmony_ci{
979f9f848faSopenharmony_ci	if (dev->desc && (dev->flags & DF_DESCMALLOCED)) {
980f9f848faSopenharmony_ci		bsd_free(dev->desc, M_BUS);
981f9f848faSopenharmony_ci		dev->flags &= ~DF_DESCMALLOCED;
982f9f848faSopenharmony_ci		dev->desc = NULL;
983f9f848faSopenharmony_ci	}
984f9f848faSopenharmony_ci
985f9f848faSopenharmony_ci	if (copy && desc) {
986f9f848faSopenharmony_ci		dev->desc = bsd_malloc(strlen(desc) + 1, M_BUS, M_NOWAIT);
987f9f848faSopenharmony_ci		if (dev->desc) {
988f9f848faSopenharmony_ci			if (strcpy_s(dev->desc, strlen(desc) + 1, desc) != EOK) {
989f9f848faSopenharmony_ci				PDEBUG(("desc internal copy desc failed!\n"));
990f9f848faSopenharmony_ci			}
991f9f848faSopenharmony_ci			dev->flags |= DF_DESCMALLOCED;
992f9f848faSopenharmony_ci		}
993f9f848faSopenharmony_ci	} else {
994f9f848faSopenharmony_ci		/* Avoid a -Wcast-qual warning */
995f9f848faSopenharmony_ci		dev->desc = (char *)(uintptr_t) desc;
996f9f848faSopenharmony_ci	}
997f9f848faSopenharmony_ci
998f9f848faSopenharmony_ci	bus_data_generation_update();
999f9f848faSopenharmony_ci}
1000f9f848faSopenharmony_ci
1001f9f848faSopenharmony_ci/**
1002f9f848faSopenharmony_ci * @brief Set the device's description
1003f9f848faSopenharmony_ci *
1004f9f848faSopenharmony_ci * The value of @c desc should be a string constant that will not
1005f9f848faSopenharmony_ci * change (at least until the description is changed in a subsequent
1006f9f848faSopenharmony_ci * call to device_set_desc() or device_set_desc_copy()).
1007f9f848faSopenharmony_ci */
1008f9f848faSopenharmony_civoid
1009f9f848faSopenharmony_cidevice_set_desc(device_t dev, const char* desc)
1010f9f848faSopenharmony_ci{
1011f9f848faSopenharmony_ci	device_set_desc_internal(dev, desc, FALSE);
1012f9f848faSopenharmony_ci}
1013f9f848faSopenharmony_ci
1014f9f848faSopenharmony_ci/**
1015f9f848faSopenharmony_ci * @brief Set the device's description
1016f9f848faSopenharmony_ci *
1017f9f848faSopenharmony_ci * The string pointed to by @c desc is copied. Use this function if
1018f9f848faSopenharmony_ci * the device description is generated, (e.g. with sprintf()).
1019f9f848faSopenharmony_ci */
1020f9f848faSopenharmony_civoid
1021f9f848faSopenharmony_cidevice_set_desc_copy(device_t dev, const char* desc)
1022f9f848faSopenharmony_ci{
1023f9f848faSopenharmony_ci        device_set_desc_internal(dev, desc, TRUE);
1024f9f848faSopenharmony_ci}
1025f9f848faSopenharmony_ci
1026f9f848faSopenharmony_ci/**
1027f9f848faSopenharmony_ci * @brief Return the device's description string
1028f9f848faSopenharmony_ci */
1029f9f848faSopenharmony_ciconst char *
1030f9f848faSopenharmony_cidevice_get_desc(device_t dev)
1031f9f848faSopenharmony_ci{
1032f9f848faSopenharmony_ci        return (dev->desc);
1033f9f848faSopenharmony_ci}
1034f9f848faSopenharmony_ci
1035f9f848faSopenharmony_ci/**
1036f9f848faSopenharmony_ci * @brief Return the device's softc field
1037f9f848faSopenharmony_ci *
1038f9f848faSopenharmony_ci * The softc is allocated and zeroed when a driver is attached, based
1039f9f848faSopenharmony_ci * on the size field of the driver.
1040f9f848faSopenharmony_ci */
1041f9f848faSopenharmony_civoid *
1042f9f848faSopenharmony_cidevice_get_softc(device_t dev)
1043f9f848faSopenharmony_ci{
1044f9f848faSopenharmony_ci        return (dev->softc);
1045f9f848faSopenharmony_ci}
1046f9f848faSopenharmony_ci
1047f9f848faSopenharmony_ci/**
1048f9f848faSopenharmony_ci * @brief Set the device's softc field
1049f9f848faSopenharmony_ci *
1050f9f848faSopenharmony_ci * Most drivers do not need to use this since the softc is allocated
1051f9f848faSopenharmony_ci * automatically when the driver is attached.
1052f9f848faSopenharmony_ci */
1053f9f848faSopenharmony_civoid
1054f9f848faSopenharmony_cidevice_set_softc(device_t dev, void *softc)
1055f9f848faSopenharmony_ci{
1056f9f848faSopenharmony_ci        if (dev->softc && !(dev->flags & DF_EXTERNALSOFTC))
1057f9f848faSopenharmony_ci                bsd_free(dev->softc, M_BUS_SC);
1058f9f848faSopenharmony_ci        dev->softc = softc;
1059f9f848faSopenharmony_ci        if (dev->softc)
1060f9f848faSopenharmony_ci                dev->flags |= DF_EXTERNALSOFTC;
1061f9f848faSopenharmony_ci        else
1062f9f848faSopenharmony_ci                dev->flags &= ~DF_EXTERNALSOFTC;
1063f9f848faSopenharmony_ci}
1064f9f848faSopenharmony_ci
1065f9f848faSopenharmony_ci/**
1066f9f848faSopenharmony_ci * @brief Free claimed softc
1067f9f848faSopenharmony_ci *
1068f9f848faSopenharmony_ci * Most drivers do not need to use this since the softc is freed
1069f9f848faSopenharmony_ci * automatically when the driver is detached.
1070f9f848faSopenharmony_ci */
1071f9f848faSopenharmony_civoid
1072f9f848faSopenharmony_cidevice_free_softc(void *softc)
1073f9f848faSopenharmony_ci{
1074f9f848faSopenharmony_ci        bsd_free(softc, M_BUS_SC);
1075f9f848faSopenharmony_ci}
1076f9f848faSopenharmony_ci
1077f9f848faSopenharmony_ci/**
1078f9f848faSopenharmony_ci * @brief Claim softc
1079f9f848faSopenharmony_ci *
1080f9f848faSopenharmony_ci * This function can be used to let the driver free the automatically
1081f9f848faSopenharmony_ci * allocated softc using "device_free_softc()". This function is
1082f9f848faSopenharmony_ci * useful when the driver is refcounting the softc and the softc
1083f9f848faSopenharmony_ci * cannot be freed when the "device_detach" method is called.
1084f9f848faSopenharmony_ci */
1085f9f848faSopenharmony_civoid
1086f9f848faSopenharmony_cidevice_claim_softc(device_t dev)
1087f9f848faSopenharmony_ci{
1088f9f848faSopenharmony_ci        if (dev->softc)
1089f9f848faSopenharmony_ci                dev->flags |= DF_EXTERNALSOFTC;
1090f9f848faSopenharmony_ci        else
1091f9f848faSopenharmony_ci                dev->flags &= ~DF_EXTERNALSOFTC;
1092f9f848faSopenharmony_ci}
1093f9f848faSopenharmony_ci
1094f9f848faSopenharmony_ci/**
1095f9f848faSopenharmony_ci * @brief Get the device's ivars field
1096f9f848faSopenharmony_ci *
1097f9f848faSopenharmony_ci * The ivars field is used by the parent device to store per-device
1098f9f848faSopenharmony_ci * state (e.g. the physical location of the device or a list of
1099f9f848faSopenharmony_ci * resources).
1100f9f848faSopenharmony_ci */
1101f9f848faSopenharmony_civoid *
1102f9f848faSopenharmony_cidevice_get_ivars(device_t dev)
1103f9f848faSopenharmony_ci{
1104f9f848faSopenharmony_ci
1105f9f848faSopenharmony_ci        KASSERT(dev != NULL, ("device_get_ivars(NULL, ...)"));
1106f9f848faSopenharmony_ci        return (dev->ivars);
1107f9f848faSopenharmony_ci}
1108f9f848faSopenharmony_ci
1109f9f848faSopenharmony_ci/**
1110f9f848faSopenharmony_ci * @brief Set the device's ivars field
1111f9f848faSopenharmony_ci */
1112f9f848faSopenharmony_civoid
1113f9f848faSopenharmony_cidevice_set_ivars(device_t dev, void * ivars)
1114f9f848faSopenharmony_ci{
1115f9f848faSopenharmony_ci
1116f9f848faSopenharmony_ci        KASSERT(dev != NULL, ("device_set_ivars(NULL, ...)"));
1117f9f848faSopenharmony_ci        dev->ivars = ivars;
1118f9f848faSopenharmony_ci}
1119f9f848faSopenharmony_ci
1120f9f848faSopenharmony_ci/**
1121f9f848faSopenharmony_ci * @brief Return the device's state
1122f9f848faSopenharmony_ci */
1123f9f848faSopenharmony_cidevice_state_t
1124f9f848faSopenharmony_cidevice_get_state(device_t dev)
1125f9f848faSopenharmony_ci{
1126f9f848faSopenharmony_ci        return (dev->state);
1127f9f848faSopenharmony_ci}
1128f9f848faSopenharmony_ci
1129f9f848faSopenharmony_ci/**
1130f9f848faSopenharmony_ci * @brief Set the DF_ENABLED flag for the device
1131f9f848faSopenharmony_ci */
1132f9f848faSopenharmony_civoid
1133f9f848faSopenharmony_cidevice_enable(device_t dev)
1134f9f848faSopenharmony_ci{
1135f9f848faSopenharmony_ci        dev->flags |= DF_ENABLED;
1136f9f848faSopenharmony_ci}
1137f9f848faSopenharmony_ci
1138f9f848faSopenharmony_ci/**
1139f9f848faSopenharmony_ci * @brief Clear the DF_ENABLED flag for the device
1140f9f848faSopenharmony_ci */
1141f9f848faSopenharmony_civoid
1142f9f848faSopenharmony_cidevice_disable(device_t dev)
1143f9f848faSopenharmony_ci{
1144f9f848faSopenharmony_ci        dev->flags &= ~DF_ENABLED;
1145f9f848faSopenharmony_ci}
1146f9f848faSopenharmony_ci
1147f9f848faSopenharmony_ci/**
1148f9f848faSopenharmony_ci * @brief Increment the busy counter for the device
1149f9f848faSopenharmony_ci */
1150f9f848faSopenharmony_civoid
1151f9f848faSopenharmony_cidevice_busy(device_t dev)
1152f9f848faSopenharmony_ci{
1153f9f848faSopenharmony_ci        if (dev->state < DS_ATTACHING)
1154f9f848faSopenharmony_ci                panic("device_busy: called for unattached device");
1155f9f848faSopenharmony_ci        if (dev->busy == 0 && dev->parent)
1156f9f848faSopenharmony_ci                device_busy(dev->parent);
1157f9f848faSopenharmony_ci        dev->busy++;
1158f9f848faSopenharmony_ci        if (dev->state == DS_ATTACHED)
1159f9f848faSopenharmony_ci                dev->state = DS_BUSY;
1160f9f848faSopenharmony_ci}
1161f9f848faSopenharmony_ci
1162f9f848faSopenharmony_ci/**
1163f9f848faSopenharmony_ci * @brief Decrement the busy counter for the device
1164f9f848faSopenharmony_ci */
1165f9f848faSopenharmony_civoid
1166f9f848faSopenharmony_cidevice_unbusy(device_t dev)
1167f9f848faSopenharmony_ci{
1168f9f848faSopenharmony_ci        if (dev->busy != 0 && dev->state != DS_BUSY &&
1169f9f848faSopenharmony_ci            dev->state != DS_ATTACHING)
1170f9f848faSopenharmony_ci                panic("device_unbusy: called for non-busy device %s",
1171f9f848faSopenharmony_ci                    device_get_nameunit(dev));
1172f9f848faSopenharmony_ci        dev->busy--;
1173f9f848faSopenharmony_ci        if (dev->busy == 0) {
1174f9f848faSopenharmony_ci                if (dev->parent)
1175f9f848faSopenharmony_ci                        device_unbusy(dev->parent);
1176f9f848faSopenharmony_ci                if (dev->state == DS_BUSY)
1177f9f848faSopenharmony_ci                        dev->state = DS_ATTACHED;
1178f9f848faSopenharmony_ci        }
1179f9f848faSopenharmony_ci}
1180f9f848faSopenharmony_ci
1181f9f848faSopenharmony_ci/**
1182f9f848faSopenharmony_ci * @brief Set the DF_QUIET flag for the device
1183f9f848faSopenharmony_ci */
1184f9f848faSopenharmony_civoid
1185f9f848faSopenharmony_cidevice_quiet(device_t dev)
1186f9f848faSopenharmony_ci{
1187f9f848faSopenharmony_ci        dev->flags |= DF_QUIET;
1188f9f848faSopenharmony_ci}
1189f9f848faSopenharmony_ci
1190f9f848faSopenharmony_ci/**
1191f9f848faSopenharmony_ci * @brief Clear the DF_QUIET flag for the device
1192f9f848faSopenharmony_ci */
1193f9f848faSopenharmony_civoid
1194f9f848faSopenharmony_cidevice_verbose(device_t dev)
1195f9f848faSopenharmony_ci{
1196f9f848faSopenharmony_ci        dev->flags &= ~DF_QUIET;
1197f9f848faSopenharmony_ci}
1198f9f848faSopenharmony_ci
1199f9f848faSopenharmony_ci/**
1200f9f848faSopenharmony_ci * @brief Return non-zero if the DF_QUIET flag is set on the device
1201f9f848faSopenharmony_ci */
1202f9f848faSopenharmony_ciint
1203f9f848faSopenharmony_cidevice_is_quiet(device_t dev)
1204f9f848faSopenharmony_ci{
1205f9f848faSopenharmony_ci        return ((dev->flags & DF_QUIET) != 0);
1206f9f848faSopenharmony_ci}
1207f9f848faSopenharmony_ci
1208f9f848faSopenharmony_ci/**
1209f9f848faSopenharmony_ci * @brief Return non-zero if the DF_ENABLED flag is set on the device
1210f9f848faSopenharmony_ci */
1211f9f848faSopenharmony_ciint
1212f9f848faSopenharmony_cidevice_is_enabled(device_t dev)
1213f9f848faSopenharmony_ci{
1214f9f848faSopenharmony_ci        return ((dev->flags & DF_ENABLED) != 0);
1215f9f848faSopenharmony_ci}
1216f9f848faSopenharmony_ci
1217f9f848faSopenharmony_ci/**
1218f9f848faSopenharmony_ci * @brief Return non-zero if the device was successfully probed
1219f9f848faSopenharmony_ci */
1220f9f848faSopenharmony_ciint
1221f9f848faSopenharmony_cidevice_is_alive(device_t dev)
1222f9f848faSopenharmony_ci{
1223f9f848faSopenharmony_ci        return (dev->state >= DS_ALIVE);
1224f9f848faSopenharmony_ci}
1225f9f848faSopenharmony_ci
1226f9f848faSopenharmony_ci/**
1227f9f848faSopenharmony_ci * @brief Return non-zero if the device currently has a driver
1228f9f848faSopenharmony_ci * attached to it
1229f9f848faSopenharmony_ci */
1230f9f848faSopenharmony_ciint
1231f9f848faSopenharmony_cidevice_is_attached(device_t dev)
1232f9f848faSopenharmony_ci{
1233f9f848faSopenharmony_ci        return (dev->state >= DS_ATTACHED);
1234f9f848faSopenharmony_ci}
1235f9f848faSopenharmony_ci
1236f9f848faSopenharmony_ci/**
1237f9f848faSopenharmony_ci * @brief Return non-zero if the device is currently suspended.
1238f9f848faSopenharmony_ci */
1239f9f848faSopenharmony_ciint
1240f9f848faSopenharmony_cidevice_is_suspended(device_t dev)
1241f9f848faSopenharmony_ci{
1242f9f848faSopenharmony_ci        return ((dev->flags & DF_SUSPENDED) != 0);
1243f9f848faSopenharmony_ci}
1244f9f848faSopenharmony_ci
1245f9f848faSopenharmony_ci
1246f9f848faSopenharmony_ci
1247f9f848faSopenharmony_ci/**
1248f9f848faSopenharmony_ci * @brief Return a string containing the device's devclass name
1249f9f848faSopenharmony_ci * followed by an ascii representation of the device's unit number
1250f9f848faSopenharmony_ci * (e.g. @c "foo2").
1251f9f848faSopenharmony_ci */
1252f9f848faSopenharmony_ciconst char *
1253f9f848faSopenharmony_cidevice_get_nameunit(device_t dev)
1254f9f848faSopenharmony_ci{
1255f9f848faSopenharmony_ci	return (dev->nameunit);
1256f9f848faSopenharmony_ci}
1257f9f848faSopenharmony_ci
1258f9f848faSopenharmony_ci/**
1259f9f848faSopenharmony_ci * @internal
1260f9f848faSopenharmony_ci * @brief Add a device to a devclass
1261f9f848faSopenharmony_ci *
1262f9f848faSopenharmony_ci * A unit number is allocated for the device (using the device's
1263f9f848faSopenharmony_ci * preferred unit number if any) and the device is registered in the
1264f9f848faSopenharmony_ci * devclass. This allows the device to be looked up by its unit
1265f9f848faSopenharmony_ci * number, e.g. by decoding a dev_t minor number.
1266f9f848faSopenharmony_ci *
1267f9f848faSopenharmony_ci * @param dc            the devclass to add to
1268f9f848faSopenharmony_ci * @param dev           the device to add
1269f9f848faSopenharmony_ci *
1270f9f848faSopenharmony_ci * @retval 0            success
1271f9f848faSopenharmony_ci * @retval EEXIST       the requested unit number is already allocated
1272f9f848faSopenharmony_ci * @retval ENOMEM       memory allocation failure
1273f9f848faSopenharmony_ci */
1274f9f848faSopenharmony_cistatic int
1275f9f848faSopenharmony_cidevclass_add_device(devclass_t dc, device_t dev)
1276f9f848faSopenharmony_ci{
1277f9f848faSopenharmony_ci        int buflen, error;
1278f9f848faSopenharmony_ci
1279f9f848faSopenharmony_ci        PDEBUG(("%s in devclass %s", DEVICENAME(dev), DEVCLANAME(dc)));
1280f9f848faSopenharmony_ci
1281f9f848faSopenharmony_ci        buflen = snprintf(NULL, 0, "%s%d$", dc->name, INT_MAX);
1282f9f848faSopenharmony_ci        if (buflen < 0)
1283f9f848faSopenharmony_ci                return (ENOMEM);
1284f9f848faSopenharmony_ci        dev->nameunit = bsd_malloc(buflen, M_BUS, M_NOWAIT|M_ZERO);
1285f9f848faSopenharmony_ci        if (!dev->nameunit)
1286f9f848faSopenharmony_ci                return (ENOMEM);
1287f9f848faSopenharmony_ci
1288f9f848faSopenharmony_ci        if ((error = devclass_alloc_unit(dc, dev, &dev->unit)) != 0) {
1289f9f848faSopenharmony_ci                bsd_free(dev->nameunit, M_BUS);
1290f9f848faSopenharmony_ci                dev->nameunit = NULL;
1291f9f848faSopenharmony_ci                return (error);
1292f9f848faSopenharmony_ci        }
1293f9f848faSopenharmony_ci        dc->devices[dev->unit] = dev;
1294f9f848faSopenharmony_ci        dev->devclass = dc;
1295f9f848faSopenharmony_ci        if (snprintf_s(dev->nameunit, buflen, buflen - 1, "%s%d", dc->name, dev->unit) < 0) {
1296f9f848faSopenharmony_ci                bsd_free(dev->nameunit, M_BUS);
1297f9f848faSopenharmony_ci                dev->nameunit = NULL;
1298f9f848faSopenharmony_ci                return (ENOMEM);
1299f9f848faSopenharmony_ci        }
1300f9f848faSopenharmony_ci        PDEBUG(("dev->nameunit : %s", dev->nameunit));
1301f9f848faSopenharmony_ci
1302f9f848faSopenharmony_ci        return (0);
1303f9f848faSopenharmony_ci}
1304f9f848faSopenharmony_ci
1305f9f848faSopenharmony_ci/**
1306f9f848faSopenharmony_ci * @internal
1307f9f848faSopenharmony_ci * @brief Delete a device from a devclass
1308f9f848faSopenharmony_ci *
1309f9f848faSopenharmony_ci * The device is removed from the devclass's device list and its unit
1310f9f848faSopenharmony_ci * number is freed.
1311f9f848faSopenharmony_ci
1312f9f848faSopenharmony_ci * @param dc            the devclass to delete from
1313f9f848faSopenharmony_ci * @param dev           the device to delete
1314f9f848faSopenharmony_ci *
1315f9f848faSopenharmony_ci * @retval 0            success
1316f9f848faSopenharmony_ci */
1317f9f848faSopenharmony_cistatic int
1318f9f848faSopenharmony_cidevclass_delete_device(devclass_t dc, device_t dev)
1319f9f848faSopenharmony_ci{
1320f9f848faSopenharmony_ci        if (!dc || !dev)
1321f9f848faSopenharmony_ci                return (0);
1322f9f848faSopenharmony_ci
1323f9f848faSopenharmony_ci        PDEBUG(("%s in devclass %s", DEVICENAME(dev), DEVCLANAME(dc)));
1324f9f848faSopenharmony_ci
1325f9f848faSopenharmony_ci        if (dev->devclass != dc || dc->devices[dev->unit] != dev)
1326f9f848faSopenharmony_ci                panic("devclass_delete_device: inconsistent device class");
1327f9f848faSopenharmony_ci        dc->devices[dev->unit] = NULL;
1328f9f848faSopenharmony_ci        if (dev->flags & DF_WILDCARD)
1329f9f848faSopenharmony_ci                dev->unit = -1;
1330f9f848faSopenharmony_ci        dev->devclass = NULL;
1331f9f848faSopenharmony_ci        bsd_free(dev->nameunit, M_BUS);
1332f9f848faSopenharmony_ci        dev->nameunit = NULL;
1333f9f848faSopenharmony_ci
1334f9f848faSopenharmony_ci        return (0);
1335f9f848faSopenharmony_ci}
1336f9f848faSopenharmony_ci
1337f9f848faSopenharmony_ci/**
1338f9f848faSopenharmony_ci * @internal
1339f9f848faSopenharmony_ci * @brief Make a new device and add it as a child of @p parent
1340f9f848faSopenharmony_ci *
1341f9f848faSopenharmony_ci * @param parent	the parent of the new device
1342f9f848faSopenharmony_ci * @param name		the devclass name of the new device or @c NULL
1343f9f848faSopenharmony_ci *			to leave the devclass unspecified
1344f9f848faSopenharmony_ci * @parem unit		the unit number of the new device of @c -1 to
1345f9f848faSopenharmony_ci *			leave the unit number unspecified
1346f9f848faSopenharmony_ci *
1347f9f848faSopenharmony_ci * @returns the new device
1348f9f848faSopenharmony_ci */
1349f9f848faSopenharmony_cistatic device_t
1350f9f848faSopenharmony_cimake_device(device_t parent, const char *name, int unit)
1351f9f848faSopenharmony_ci{
1352f9f848faSopenharmony_ci	device_t dev;
1353f9f848faSopenharmony_ci	devclass_t dc;
1354f9f848faSopenharmony_ci
1355f9f848faSopenharmony_ci	PDEBUG(("%s at %s as unit %d", name, DEVICENAME(parent), unit));
1356f9f848faSopenharmony_ci
1357f9f848faSopenharmony_ci	if (name) {
1358f9f848faSopenharmony_ci		dc = devclass_find_internal(name, NULL, TRUE);
1359f9f848faSopenharmony_ci		if (!dc) {
1360f9f848faSopenharmony_ci			printf("make_device: can't find device class %s\n",
1361f9f848faSopenharmony_ci			    name);
1362f9f848faSopenharmony_ci			return (NULL);
1363f9f848faSopenharmony_ci		}
1364f9f848faSopenharmony_ci	} else {
1365f9f848faSopenharmony_ci		dc = NULL;
1366f9f848faSopenharmony_ci	}
1367f9f848faSopenharmony_ci
1368f9f848faSopenharmony_ci	dev = bsd_malloc(sizeof(struct device), 0, M_NOWAIT|M_ZERO);
1369f9f848faSopenharmony_ci	if (!dev)
1370f9f848faSopenharmony_ci		return (NULL);
1371f9f848faSopenharmony_ci
1372f9f848faSopenharmony_ci	dev->parent = parent;
1373f9f848faSopenharmony_ci	TAILQ_INIT(&dev->children);
1374f9f848faSopenharmony_ci	kobj_init((kobj_t) dev, &null_class);
1375f9f848faSopenharmony_ci	dev->driver = NULL;
1376f9f848faSopenharmony_ci	dev->devclass = NULL;
1377f9f848faSopenharmony_ci	dev->unit = unit;
1378f9f848faSopenharmony_ci	dev->nameunit = NULL;
1379f9f848faSopenharmony_ci	dev->desc = NULL;
1380f9f848faSopenharmony_ci	dev->busy = 0;
1381f9f848faSopenharmony_ci	dev->devflags = 0;
1382f9f848faSopenharmony_ci	dev->flags = DF_ENABLED;
1383f9f848faSopenharmony_ci	dev->order = 0;
1384f9f848faSopenharmony_ci	if (unit == -1)
1385f9f848faSopenharmony_ci		dev->flags |= DF_WILDCARD;
1386f9f848faSopenharmony_ci	if (name) {
1387f9f848faSopenharmony_ci		dev->flags |= DF_FIXEDCLASS;
1388f9f848faSopenharmony_ci		if (devclass_add_device(dc, dev)) {
1389f9f848faSopenharmony_ci			kobj_delete((kobj_t) dev, NULL);
1390f9f848faSopenharmony_ci			return (NULL);
1391f9f848faSopenharmony_ci		}
1392f9f848faSopenharmony_ci	}
1393f9f848faSopenharmony_ci	dev->ivars = NULL;
1394f9f848faSopenharmony_ci	dev->softc = NULL;
1395f9f848faSopenharmony_ci
1396f9f848faSopenharmony_ci	dev->state = DS_NOTPRESENT;
1397f9f848faSopenharmony_ci
1398f9f848faSopenharmony_ci	PDEBUG(("bus_data_devices (%p) ", &bus_data_devices));
1399f9f848faSopenharmony_ci	TAILQ_INSERT_TAIL(&bus_data_devices, dev, devlink);
1400f9f848faSopenharmony_ci	bus_data_generation_update();
1401f9f848faSopenharmony_ci
1402f9f848faSopenharmony_ci	PDEBUG(("%s at %s as unit %d success", name, DEVICENAME(parent), unit));
1403f9f848faSopenharmony_ci	return (dev);
1404f9f848faSopenharmony_ci}
1405f9f848faSopenharmony_ci
1406f9f848faSopenharmony_ci/**
1407f9f848faSopenharmony_ci * @internal
1408f9f848faSopenharmony_ci * @brief Print a description of a device.
1409f9f848faSopenharmony_ci */
1410f9f848faSopenharmony_cistatic int
1411f9f848faSopenharmony_cidevice_print_child(device_t dev, device_t child)
1412f9f848faSopenharmony_ci{
1413f9f848faSopenharmony_ci        int retval = 0;
1414f9f848faSopenharmony_ci
1415f9f848faSopenharmony_ci        if (device_is_alive(child))
1416f9f848faSopenharmony_ci                retval += BUS_PRINT_CHILD(dev, child);
1417f9f848faSopenharmony_ci        else
1418f9f848faSopenharmony_ci                retval += device_printf(child, " not found\n");
1419f9f848faSopenharmony_ci
1420f9f848faSopenharmony_ci        return (retval);
1421f9f848faSopenharmony_ci}
1422f9f848faSopenharmony_ci
1423f9f848faSopenharmony_ci/**
1424f9f848faSopenharmony_ci * @brief Create a new device
1425f9f848faSopenharmony_ci *
1426f9f848faSopenharmony_ci * This creates a new device and adds it as a child of an existing
1427f9f848faSopenharmony_ci * parent device. The new device will be added after the last existing
1428f9f848faSopenharmony_ci * child with order zero.
1429f9f848faSopenharmony_ci *
1430f9f848faSopenharmony_ci * @param dev		the device which will be the parent of the
1431f9f848faSopenharmony_ci *			new child device
1432f9f848faSopenharmony_ci * @param name		devclass name for new device or @c NULL if not
1433f9f848faSopenharmony_ci *			specified
1434f9f848faSopenharmony_ci * @param unit		unit number for new device or @c -1 if not
1435f9f848faSopenharmony_ci *			specified
1436f9f848faSopenharmony_ci *
1437f9f848faSopenharmony_ci * @returns		the new device
1438f9f848faSopenharmony_ci */
1439f9f848faSopenharmony_cidevice_t
1440f9f848faSopenharmony_cidevice_add_child(device_t dev, const char *name, int unit)
1441f9f848faSopenharmony_ci{
1442f9f848faSopenharmony_ci	return (device_add_child_ordered(dev, 0, name, unit));
1443f9f848faSopenharmony_ci}
1444f9f848faSopenharmony_ci
1445f9f848faSopenharmony_cidevice_t
1446f9f848faSopenharmony_cibus_get_device(device_t dev, const char *name)
1447f9f848faSopenharmony_ci{
1448f9f848faSopenharmony_ci        device_t child;
1449f9f848faSopenharmony_ci
1450f9f848faSopenharmony_ci        PDEBUG(("+"));
1451f9f848faSopenharmony_ci        TAILQ_FOREACH(child, &dev->children, link) {
1452f9f848faSopenharmony_ci                if (!strcmp(device_get_name(child), name))
1453f9f848faSopenharmony_ci                        return (child);
1454f9f848faSopenharmony_ci        }
1455f9f848faSopenharmony_ci        PDEBUG(("-"));
1456f9f848faSopenharmony_ci        return (NULL);
1457f9f848faSopenharmony_ci}
1458f9f848faSopenharmony_ci
1459f9f848faSopenharmony_ci/**
1460f9f848faSopenharmony_ci * @brief Create a new device
1461f9f848faSopenharmony_ci *
1462f9f848faSopenharmony_ci * This creates a new device and adds it as a child of an existing
1463f9f848faSopenharmony_ci * parent device. The new device will be added after the last existing
1464f9f848faSopenharmony_ci * child with the same order.
1465f9f848faSopenharmony_ci *
1466f9f848faSopenharmony_ci * @param dev		the device which will be the parent of the
1467f9f848faSopenharmony_ci *			new child device
1468f9f848faSopenharmony_ci * @param order		a value which is used to partially sort the
1469f9f848faSopenharmony_ci *			children of @p dev - devices created using
1470f9f848faSopenharmony_ci *			lower values of @p order appear first in @p
1471f9f848faSopenharmony_ci *			dev's list of children
1472f9f848faSopenharmony_ci * @param name		devclass name for new device or @c NULL if not
1473f9f848faSopenharmony_ci *			specified
1474f9f848faSopenharmony_ci * @param unit		unit number for new device or @c -1 if not
1475f9f848faSopenharmony_ci *			specified
1476f9f848faSopenharmony_ci *
1477f9f848faSopenharmony_ci * @returns		the new device
1478f9f848faSopenharmony_ci */
1479f9f848faSopenharmony_cidevice_t
1480f9f848faSopenharmony_cidevice_add_child_ordered(device_t dev, u_int order, const char *name, int unit)
1481f9f848faSopenharmony_ci{
1482f9f848faSopenharmony_ci	device_t child;
1483f9f848faSopenharmony_ci	device_t place;
1484f9f848faSopenharmony_ci
1485f9f848faSopenharmony_ci	PDEBUG(("%s at %s with order %u as unit %d",
1486f9f848faSopenharmony_ci	    name, DEVICENAME(dev), order, unit));
1487f9f848faSopenharmony_ci	KASSERT(name != NULL || unit == -1,
1488f9f848faSopenharmony_ci	    ("child device with wildcard name and specific unit number"));
1489f9f848faSopenharmony_ci
1490f9f848faSopenharmony_ci	child = make_device(dev, name, unit);
1491f9f848faSopenharmony_ci	if (child == NULL)
1492f9f848faSopenharmony_ci		return (child);
1493f9f848faSopenharmony_ci	child->order = order;
1494f9f848faSopenharmony_ci
1495f9f848faSopenharmony_ci	TAILQ_FOREACH(place, &dev->children, link) {
1496f9f848faSopenharmony_ci		if (place->order > order)
1497f9f848faSopenharmony_ci			break;
1498f9f848faSopenharmony_ci	}
1499f9f848faSopenharmony_ci
1500f9f848faSopenharmony_ci	if (place) {
1501f9f848faSopenharmony_ci		/*
1502f9f848faSopenharmony_ci		 * The device 'place' is the first device whose order is
1503f9f848faSopenharmony_ci		 * greater than the new child.
1504f9f848faSopenharmony_ci		 */
1505f9f848faSopenharmony_ci		TAILQ_INSERT_BEFORE(place, child, link);
1506f9f848faSopenharmony_ci	} else {
1507f9f848faSopenharmony_ci		/*
1508f9f848faSopenharmony_ci		 * The new child's order is greater or equal to the order of
1509f9f848faSopenharmony_ci		 * any existing device. Add the child to the tail of the list.
1510f9f848faSopenharmony_ci		 */
1511f9f848faSopenharmony_ci		TAILQ_INSERT_TAIL(&dev->children, child, link);
1512f9f848faSopenharmony_ci	}
1513f9f848faSopenharmony_ci
1514f9f848faSopenharmony_ci	bus_data_generation_update();
1515f9f848faSopenharmony_ci	PDEBUG(("%s at %s with order %u as unit %d success",
1516f9f848faSopenharmony_ci		name, DEVICENAME(dev), order, unit));
1517f9f848faSopenharmony_ci	return (child);
1518f9f848faSopenharmony_ci}
1519f9f848faSopenharmony_ci
1520f9f848faSopenharmony_ci/**
1521f9f848faSopenharmony_ci * @brief Delete a device
1522f9f848faSopenharmony_ci *
1523f9f848faSopenharmony_ci * This function deletes a device along with all of its children. If
1524f9f848faSopenharmony_ci * the device currently has a driver attached to it, the device is
1525f9f848faSopenharmony_ci * detached first using device_detach().
1526f9f848faSopenharmony_ci *
1527f9f848faSopenharmony_ci * @param dev           the parent device
1528f9f848faSopenharmony_ci * @param child         the device to delete
1529f9f848faSopenharmony_ci *
1530f9f848faSopenharmony_ci * @retval 0            success
1531f9f848faSopenharmony_ci * @retval non-zero     a unit error code describing the error
1532f9f848faSopenharmony_ci */
1533f9f848faSopenharmony_ciint
1534f9f848faSopenharmony_cidevice_delete_child(device_t dev, device_t child)
1535f9f848faSopenharmony_ci{
1536f9f848faSopenharmony_ci        int error;
1537f9f848faSopenharmony_ci        device_t grandchild;
1538f9f848faSopenharmony_ci
1539f9f848faSopenharmony_ci        PDEBUG(("%s from %s", DEVICENAME(child), DEVICENAME(dev)));
1540f9f848faSopenharmony_ci
1541f9f848faSopenharmony_ci        /* detach parent before deleting children, if any */
1542f9f848faSopenharmony_ci        if ((error = device_detach(child)) != 0)
1543f9f848faSopenharmony_ci                return (error);
1544f9f848faSopenharmony_ci
1545f9f848faSopenharmony_ci        /* remove children second */
1546f9f848faSopenharmony_ci        while ((grandchild = TAILQ_FIRST(&child->children)) != NULL) {
1547f9f848faSopenharmony_ci                error = device_delete_child(child, grandchild);
1548f9f848faSopenharmony_ci                if (error)
1549f9f848faSopenharmony_ci                        return (error);
1550f9f848faSopenharmony_ci        }
1551f9f848faSopenharmony_ci
1552f9f848faSopenharmony_ci        if (child->devclass)
1553f9f848faSopenharmony_ci                devclass_delete_device(child->devclass, child);
1554f9f848faSopenharmony_ci        if (child->parent)
1555f9f848faSopenharmony_ci                BUS_CHILD_DELETED(dev, child);
1556f9f848faSopenharmony_ci        TAILQ_REMOVE(&dev->children, child, link);
1557f9f848faSopenharmony_ci        TAILQ_REMOVE(&bus_data_devices, child, devlink);
1558f9f848faSopenharmony_ci        kobj_delete((kobj_t) child, M_BUS);
1559f9f848faSopenharmony_ci
1560f9f848faSopenharmony_ci        bus_data_generation_update();
1561f9f848faSopenharmony_ci        return (0);
1562f9f848faSopenharmony_ci}
1563f9f848faSopenharmony_ci
1564f9f848faSopenharmony_ci/**
1565f9f848faSopenharmony_ci * @brief Delete all children devices of the given device, if any.
1566f9f848faSopenharmony_ci *
1567f9f848faSopenharmony_ci * This function deletes all children devices of the given device, if
1568f9f848faSopenharmony_ci * any, using the device_delete_child() function for each device it
1569f9f848faSopenharmony_ci * finds. If a child device cannot be deleted, this function will
1570f9f848faSopenharmony_ci * return an error code.
1571f9f848faSopenharmony_ci *
1572f9f848faSopenharmony_ci * @param dev           the parent device
1573f9f848faSopenharmony_ci *
1574f9f848faSopenharmony_ci * @retval 0            success
1575f9f848faSopenharmony_ci * @retval non-zero     a device would not detach
1576f9f848faSopenharmony_ci */
1577f9f848faSopenharmony_ciint
1578f9f848faSopenharmony_cidevice_delete_children(device_t dev)
1579f9f848faSopenharmony_ci{
1580f9f848faSopenharmony_ci        device_t child;
1581f9f848faSopenharmony_ci        int error;
1582f9f848faSopenharmony_ci
1583f9f848faSopenharmony_ci        PDEBUG(("Deleting all children of %s", DEVICENAME(dev)));
1584f9f848faSopenharmony_ci
1585f9f848faSopenharmony_ci        error = 0;
1586f9f848faSopenharmony_ci
1587f9f848faSopenharmony_ci        while ((child = TAILQ_FIRST(&dev->children)) != NULL) {
1588f9f848faSopenharmony_ci                error = device_delete_child(dev, child);
1589f9f848faSopenharmony_ci                if (error) {
1590f9f848faSopenharmony_ci                        PDEBUG(("Failed deleting %s", DEVICENAME(child)));
1591f9f848faSopenharmony_ci                        break;
1592f9f848faSopenharmony_ci                }
1593f9f848faSopenharmony_ci        }
1594f9f848faSopenharmony_ci        return (error);
1595f9f848faSopenharmony_ci}
1596f9f848faSopenharmony_ci
1597f9f848faSopenharmony_ci/**
1598f9f848faSopenharmony_ci * @brief Probe a device and attach a driver if possible
1599f9f848faSopenharmony_ci *
1600f9f848faSopenharmony_ci * calls device_probe() and attaches if that was successful.
1601f9f848faSopenharmony_ci */
1602f9f848faSopenharmony_ciint
1603f9f848faSopenharmony_cidevice_probe_and_attach(device_t dev)
1604f9f848faSopenharmony_ci{
1605f9f848faSopenharmony_ci	int error;
1606f9f848faSopenharmony_ci
1607f9f848faSopenharmony_ci        PDEBUG(("+"));
1608f9f848faSopenharmony_ci	GIANT_REQUIRED;
1609f9f848faSopenharmony_ci
1610f9f848faSopenharmony_ci	error = device_probe(dev);
1611f9f848faSopenharmony_ci	if (error == -1)
1612f9f848faSopenharmony_ci		return (0);
1613f9f848faSopenharmony_ci	else if (error != 0)
1614f9f848faSopenharmony_ci		return (error);
1615f9f848faSopenharmony_ci
1616f9f848faSopenharmony_ci	//CURVNET_SET_QUIET(vnet0);
1617f9f848faSopenharmony_ci	error = device_attach(dev);
1618f9f848faSopenharmony_ci	//CURVNET_RESTORE();
1619f9f848faSopenharmony_ci        PDEBUG(("-"));
1620f9f848faSopenharmony_ci	return error;
1621f9f848faSopenharmony_ci}
1622f9f848faSopenharmony_ci
1623f9f848faSopenharmony_ci/**
1624f9f848faSopenharmony_ci * @brief Attach a device driver to a device
1625f9f848faSopenharmony_ci *
1626f9f848faSopenharmony_ci * This function is a wrapper around the DEVICE_ATTACH() driver
1627f9f848faSopenharmony_ci * method. In addition to calling DEVICE_ATTACH(), it initialises the
1628f9f848faSopenharmony_ci * device's sysctl tree, optionally prints a description of the device
1629f9f848faSopenharmony_ci * and queues a notification event for user-based device management
1630f9f848faSopenharmony_ci * services.
1631f9f848faSopenharmony_ci *
1632f9f848faSopenharmony_ci * Normally this function is only called internally from
1633f9f848faSopenharmony_ci * device_probe_and_attach().
1634f9f848faSopenharmony_ci *
1635f9f848faSopenharmony_ci * @param dev           the device to initialise
1636f9f848faSopenharmony_ci *
1637f9f848faSopenharmony_ci * @retval 0            success
1638f9f848faSopenharmony_ci * @retval ENXIO        no driver was found
1639f9f848faSopenharmony_ci * @retval ENOMEM       memory allocation failure
1640f9f848faSopenharmony_ci * @retval non-zero     some other unix error code
1641f9f848faSopenharmony_ci */
1642f9f848faSopenharmony_ciint
1643f9f848faSopenharmony_cidevice_attach(device_t dev)
1644f9f848faSopenharmony_ci{
1645f9f848faSopenharmony_ci        uint64_t attachtime;
1646f9f848faSopenharmony_ci        int error;
1647f9f848faSopenharmony_ci        PDEBUG(("+"));
1648f9f848faSopenharmony_ci
1649f9f848faSopenharmony_ci        //if (resource_disabled(dev->driver->name, dev->unit)) {
1650f9f848faSopenharmony_ci        //        device_disable(dev);
1651f9f848faSopenharmony_ci        //        if (bootverbose)
1652f9f848faSopenharmony_ci        //                 device_printf(dev, "disabled via hints entry\n");
1653f9f848faSopenharmony_ci        //        return (ENXIO);
1654f9f848faSopenharmony_ci        //}
1655f9f848faSopenharmony_ci
1656f9f848faSopenharmony_ci        //device_sysctl_init(dev);
1657f9f848faSopenharmony_ci        if (!device_is_quiet(dev))
1658f9f848faSopenharmony_ci                device_print_child(dev->parent, dev);
1659f9f848faSopenharmony_ci        // attachtime = get_cyclecount();
1660f9f848faSopenharmony_ci        dev->state = DS_ATTACHING;
1661f9f848faSopenharmony_ci        if ((error = DEVICE_ATTACH(dev)) != 0) {
1662f9f848faSopenharmony_ci                printf("device_attach: %s%d attach returned %d\n",
1663f9f848faSopenharmony_ci                    dev->driver->name, dev->unit, error);
1664f9f848faSopenharmony_ci                if (!(dev->flags & DF_FIXEDCLASS))
1665f9f848faSopenharmony_ci                        devclass_delete_device(dev->devclass, dev);
1666f9f848faSopenharmony_ci                (void)device_set_driver(dev, NULL);
1667f9f848faSopenharmony_ci                //device_sysctl_fini(dev);
1668f9f848faSopenharmony_ci                KASSERT(dev->busy == 0, ("attach failed but busy"));
1669f9f848faSopenharmony_ci                dev->state = DS_NOTPRESENT;
1670f9f848faSopenharmony_ci                return (error);
1671f9f848faSopenharmony_ci        }
1672f9f848faSopenharmony_ci        // attachtime = get_cyclecount() - attachtime;
1673f9f848faSopenharmony_ci        /*
1674f9f848faSopenharmony_ci         * 4 bits per device is a reasonable value for desktop and server
1675f9f848faSopenharmony_ci         * hardware with good get_cyclecount() implementations, but WILL
1676f9f848faSopenharmony_ci         * need to be adjusted on other platforms.
1677f9f848faSopenharmony_ci         */
1678f9f848faSopenharmony_ci#define RANDOM_PROBE_BIT_GUESS  4
1679f9f848faSopenharmony_ci        if (bootverbose)
1680f9f848faSopenharmony_ci                printf("random: harvesting attach, %zu bytes (%d bits) from %s%d\n",
1681f9f848faSopenharmony_ci                    sizeof(attachtime), RANDOM_PROBE_BIT_GUESS,
1682f9f848faSopenharmony_ci                    dev->driver->name, dev->unit);
1683f9f848faSopenharmony_ci        //random_harvest_direct(&attachtime, sizeof(attachtime),
1684f9f848faSopenharmony_ci        //    RANDOM_PROBE_BIT_GUESS, RANDOM_ATTACH);
1685f9f848faSopenharmony_ci        //device_sysctl_update(dev);
1686f9f848faSopenharmony_ci        if (dev->busy)
1687f9f848faSopenharmony_ci                dev->state = DS_BUSY;
1688f9f848faSopenharmony_ci        else
1689f9f848faSopenharmony_ci                dev->state = DS_ATTACHED;
1690f9f848faSopenharmony_ci        dev->flags &= ~DF_DONENOMATCH;
1691f9f848faSopenharmony_ci        //EVENTHANDLER_INVOKE(device_attach, dev);
1692f9f848faSopenharmony_ci        //devadded(dev);
1693f9f848faSopenharmony_ci        PDEBUG(("-"));
1694f9f848faSopenharmony_ci        return (0);
1695f9f848faSopenharmony_ci}
1696f9f848faSopenharmony_ci
1697f9f848faSopenharmony_ci/**
1698f9f848faSopenharmony_ci * @brief Probe a device, and return this status.
1699f9f848faSopenharmony_ci *
1700f9f848faSopenharmony_ci * This function is the core of the device autoconfiguration
1701f9f848faSopenharmony_ci * system. Its purpose is to select a suitable driver for a device and
1702f9f848faSopenharmony_ci * then call that driver to initialise the hardware appropriately. The
1703f9f848faSopenharmony_ci * driver is selected by calling the DEVICE_PROBE() method of a set of
1704f9f848faSopenharmony_ci * candidate drivers and then choosing the driver which returned the
1705f9f848faSopenharmony_ci * best value. This driver is then attached to the device using
1706f9f848faSopenharmony_ci * device_attach().
1707f9f848faSopenharmony_ci *
1708f9f848faSopenharmony_ci * The set of suitable drivers is taken from the list of drivers in
1709f9f848faSopenharmony_ci * the parent device's devclass. If the device was originally created
1710f9f848faSopenharmony_ci * with a specific class name (see device_add_child()), only drivers
1711f9f848faSopenharmony_ci * with that name are probed, otherwise all drivers in the devclass
1712f9f848faSopenharmony_ci * are probed. If no drivers return successful probe values in the
1713f9f848faSopenharmony_ci * parent devclass, the search continues in the parent of that
1714f9f848faSopenharmony_ci * devclass (see devclass_get_parent()) if any.
1715f9f848faSopenharmony_ci *
1716f9f848faSopenharmony_ci * @param dev		the device to initialise
1717f9f848faSopenharmony_ci *
1718f9f848faSopenharmony_ci * @retval 0		success
1719f9f848faSopenharmony_ci * @retval ENXIO	no driver was found
1720f9f848faSopenharmony_ci * @retval ENOMEM	memory allocation failure
1721f9f848faSopenharmony_ci * @retval non-zero	some other unix error code
1722f9f848faSopenharmony_ci * @retval -1		Device already attached
1723f9f848faSopenharmony_ci */
1724f9f848faSopenharmony_ciint
1725f9f848faSopenharmony_cidevice_probe(device_t dev)
1726f9f848faSopenharmony_ci{
1727f9f848faSopenharmony_ci	int error;
1728f9f848faSopenharmony_ci
1729f9f848faSopenharmony_ci	GIANT_REQUIRED;
1730f9f848faSopenharmony_ci        PDEBUG(("+"));
1731f9f848faSopenharmony_ci
1732f9f848faSopenharmony_ci	if (dev->state >= DS_ALIVE && (dev->flags & DF_REBID) == 0)
1733f9f848faSopenharmony_ci		return (-1);
1734f9f848faSopenharmony_ci
1735f9f848faSopenharmony_ci	if (!(dev->flags & DF_ENABLED)) {
1736f9f848faSopenharmony_ci		if (bootverbose && device_get_name(dev) != NULL) {
1737f9f848faSopenharmony_ci			device_print_prettyname(dev);
1738f9f848faSopenharmony_ci			printf("not probed (disabled)\n");
1739f9f848faSopenharmony_ci		}
1740f9f848faSopenharmony_ci		return (-1);
1741f9f848faSopenharmony_ci	}
1742f9f848faSopenharmony_ci	if ((error = device_probe_child(dev->parent, dev)) != 0) {
1743f9f848faSopenharmony_ci		if (bus_current_pass == BUS_PASS_DEFAULT &&
1744f9f848faSopenharmony_ci		    !(dev->flags & DF_DONENOMATCH)) {
1745f9f848faSopenharmony_ci			BUS_PROBE_NOMATCH(dev->parent, dev);
1746f9f848faSopenharmony_ci			//devnomatch(dev);
1747f9f848faSopenharmony_ci			dev->flags |= DF_DONENOMATCH;
1748f9f848faSopenharmony_ci		}
1749f9f848faSopenharmony_ci		return (error);
1750f9f848faSopenharmony_ci	}
1751f9f848faSopenharmony_ci        PDEBUG(("-"));
1752f9f848faSopenharmony_ci	return (0);
1753f9f848faSopenharmony_ci}
1754f9f848faSopenharmony_ci
1755f9f848faSopenharmony_ci/**
1756f9f848faSopenharmony_ci * @brief Tells a driver to quiesce itself.
1757f9f848faSopenharmony_ci *
1758f9f848faSopenharmony_ci * This function is a wrapper around the DEVICE_QUIESCE() driver
1759f9f848faSopenharmony_ci * method. If the call to DEVICE_QUIESCE() succeeds.
1760f9f848faSopenharmony_ci *
1761f9f848faSopenharmony_ci * @param dev           the device to quiesce
1762f9f848faSopenharmony_ci *
1763f9f848faSopenharmony_ci * @retval 0            success
1764f9f848faSopenharmony_ci * @retval ENXIO        no driver was found
1765f9f848faSopenharmony_ci * @retval ENOMEM       memory allocation failure
1766f9f848faSopenharmony_ci * @retval non-zero     some other unix error code
1767f9f848faSopenharmony_ci */
1768f9f848faSopenharmony_ciint
1769f9f848faSopenharmony_cidevice_quiesce(device_t dev)
1770f9f848faSopenharmony_ci{
1771f9f848faSopenharmony_ci
1772f9f848faSopenharmony_ci        PDEBUG(("%s", DEVICENAME(dev)));
1773f9f848faSopenharmony_ci        if (dev->state == DS_BUSY)
1774f9f848faSopenharmony_ci                return (EBUSY);
1775f9f848faSopenharmony_ci        if (dev->state != DS_ATTACHED)
1776f9f848faSopenharmony_ci                return (0);
1777f9f848faSopenharmony_ci
1778f9f848faSopenharmony_ci        return (DEVICE_QUIESCE(dev));
1779f9f848faSopenharmony_ci}
1780f9f848faSopenharmony_ci
1781f9f848faSopenharmony_ci/**
1782f9f848faSopenharmony_ci * @brief Notify a device of system shutdown
1783f9f848faSopenharmony_ci *
1784f9f848faSopenharmony_ci * This function calls the DEVICE_SHUTDOWN() driver method if the
1785f9f848faSopenharmony_ci * device currently has an attached driver.
1786f9f848faSopenharmony_ci *
1787f9f848faSopenharmony_ci * @returns the value returned by DEVICE_SHUTDOWN()
1788f9f848faSopenharmony_ci */
1789f9f848faSopenharmony_ciint
1790f9f848faSopenharmony_cidevice_shutdown(device_t dev)
1791f9f848faSopenharmony_ci{
1792f9f848faSopenharmony_ci        if (dev->state < DS_ATTACHED)
1793f9f848faSopenharmony_ci                return (0);
1794f9f848faSopenharmony_ci        return (DEVICE_SHUTDOWN(dev));
1795f9f848faSopenharmony_ci}
1796f9f848faSopenharmony_ci
1797f9f848faSopenharmony_ci// bus
1798f9f848faSopenharmony_ci//
1799f9f848faSopenharmony_ci//
1800f9f848faSopenharmony_cidevice_t
1801f9f848faSopenharmony_cibus_generic_add_child(device_t dev, u_int order, const char *name, int unit)
1802f9f848faSopenharmony_ci{
1803f9f848faSopenharmony_ci
1804f9f848faSopenharmony_ci        return (device_add_child_ordered(dev, order, name, unit));
1805f9f848faSopenharmony_ci}
1806f9f848faSopenharmony_ci
1807f9f848faSopenharmony_ci/**
1808f9f848faSopenharmony_ci * @brief Helper function for implementing DEVICE_PROBE()
1809f9f848faSopenharmony_ci *
1810f9f848faSopenharmony_ci * This function can be used to help implement the DEVICE_PROBE() for
1811f9f848faSopenharmony_ci * a bus (i.e. a device which has other devices attached to it). It
1812f9f848faSopenharmony_ci * calls the DEVICE_IDENTIFY() method of each driver in the device's
1813f9f848faSopenharmony_ci * devclass.
1814f9f848faSopenharmony_ci */
1815f9f848faSopenharmony_ciint
1816f9f848faSopenharmony_cibus_generic_probe(device_t dev)
1817f9f848faSopenharmony_ci{
1818f9f848faSopenharmony_ci        devclass_t dc = dev->devclass;
1819f9f848faSopenharmony_ci        driverlink_t dl = NULL;
1820f9f848faSopenharmony_ci        PDEBUG(("+"));
1821f9f848faSopenharmony_ci
1822f9f848faSopenharmony_ci        TAILQ_FOREACH(dl, &dc->drivers, link) {
1823f9f848faSopenharmony_ci                /*
1824f9f848faSopenharmony_ci                 * If this driver's pass is too high, then ignore it.
1825f9f848faSopenharmony_ci                 * For most drivers in the default pass, this will
1826f9f848faSopenharmony_ci                 * never be true.  For early-pass drivers they will
1827f9f848faSopenharmony_ci                 * only call the identify routines of eligible drivers
1828f9f848faSopenharmony_ci                 * when this routine is called.  Drivers for later
1829f9f848faSopenharmony_ci                 * passes should have their identify routines called
1830f9f848faSopenharmony_ci                 * on early-pass busses during BUS_NEW_PASS().
1831f9f848faSopenharmony_ci                 */
1832f9f848faSopenharmony_ci                if (dl->pass > bus_current_pass)
1833f9f848faSopenharmony_ci                        continue;
1834f9f848faSopenharmony_ci                DEVICE_IDENTIFY(dl->driver, dev);
1835f9f848faSopenharmony_ci        }
1836f9f848faSopenharmony_ci
1837f9f848faSopenharmony_ci        PDEBUG(("-"));
1838f9f848faSopenharmony_ci        return (0);
1839f9f848faSopenharmony_ci}
1840f9f848faSopenharmony_ci
1841f9f848faSopenharmony_ci/**
1842f9f848faSopenharmony_ci * @brief Helper function for implementing DEVICE_ATTACH()
1843f9f848faSopenharmony_ci *
1844f9f848faSopenharmony_ci * This function can be used to help implement the DEVICE_ATTACH() for
1845f9f848faSopenharmony_ci * a bus. It calls device_probe_and_attach() for each of the device's
1846f9f848faSopenharmony_ci * children.
1847f9f848faSopenharmony_ci */
1848f9f848faSopenharmony_ciint
1849f9f848faSopenharmony_cibus_generic_attach(device_t dev)
1850f9f848faSopenharmony_ci{
1851f9f848faSopenharmony_ci        device_t child;
1852f9f848faSopenharmony_ci
1853f9f848faSopenharmony_ci        PDEBUG(("+"));
1854f9f848faSopenharmony_ci        TAILQ_FOREACH(child, &dev->children, link) {
1855f9f848faSopenharmony_ci                device_probe_and_attach(child);
1856f9f848faSopenharmony_ci        }
1857f9f848faSopenharmony_ci        PDEBUG(("-"));
1858f9f848faSopenharmony_ci        return (0);
1859f9f848faSopenharmony_ci}
1860f9f848faSopenharmony_ci
1861f9f848faSopenharmony_ci/**
1862f9f848faSopenharmony_ci * @brief Helper function for implementing DEVICE_DETACH()
1863f9f848faSopenharmony_ci *
1864f9f848faSopenharmony_ci * This function can be used to help implement the DEVICE_DETACH() for
1865f9f848faSopenharmony_ci * a bus. It calls device_detach() for each of the device's
1866f9f848faSopenharmony_ci * children.
1867f9f848faSopenharmony_ci */
1868f9f848faSopenharmony_ciint
1869f9f848faSopenharmony_cibus_generic_detach(device_t dev)
1870f9f848faSopenharmony_ci{
1871f9f848faSopenharmony_ci        device_t child;
1872f9f848faSopenharmony_ci        int error;
1873f9f848faSopenharmony_ci
1874f9f848faSopenharmony_ci        if (dev->state != DS_ATTACHED)
1875f9f848faSopenharmony_ci                return (EBUSY);
1876f9f848faSopenharmony_ci
1877f9f848faSopenharmony_ci        /*
1878f9f848faSopenharmony_ci         * Detach children in the reverse order.
1879f9f848faSopenharmony_ci         * See bus_generic_suspend for details.
1880f9f848faSopenharmony_ci         */
1881f9f848faSopenharmony_ci        TAILQ_FOREACH_REVERSE(child, &dev->children, device_list, link) {
1882f9f848faSopenharmony_ci                if ((error = device_detach(child)) != 0)
1883f9f848faSopenharmony_ci                        return (error);
1884f9f848faSopenharmony_ci        }
1885f9f848faSopenharmony_ci
1886f9f848faSopenharmony_ci        return (0);
1887f9f848faSopenharmony_ci}
1888f9f848faSopenharmony_ci
1889f9f848faSopenharmony_ci/**
1890f9f848faSopenharmony_ci * @brief Helper function for implementing DEVICE_SHUTDOWN()
1891f9f848faSopenharmony_ci *
1892f9f848faSopenharmony_ci * This function can be used to help implement the DEVICE_SHUTDOWN()
1893f9f848faSopenharmony_ci * for a bus. It calls device_shutdown() for each of the device's
1894f9f848faSopenharmony_ci * children.
1895f9f848faSopenharmony_ci */
1896f9f848faSopenharmony_ciint
1897f9f848faSopenharmony_cibus_generic_shutdown(device_t dev)
1898f9f848faSopenharmony_ci{
1899f9f848faSopenharmony_ci        device_t child;
1900f9f848faSopenharmony_ci
1901f9f848faSopenharmony_ci        /*
1902f9f848faSopenharmony_ci         * Shut down children in the reverse order.
1903f9f848faSopenharmony_ci         * See bus_generic_suspend for details.
1904f9f848faSopenharmony_ci         */
1905f9f848faSopenharmony_ci        TAILQ_FOREACH_REVERSE(child, &dev->children, device_list, link) {
1906f9f848faSopenharmony_ci                device_shutdown(child);
1907f9f848faSopenharmony_ci        }
1908f9f848faSopenharmony_ci
1909f9f848faSopenharmony_ci        return (0);
1910f9f848faSopenharmony_ci}
1911f9f848faSopenharmony_ci
1912f9f848faSopenharmony_ci/**
1913f9f848faSopenharmony_ci * @brief Default function for suspending a child device.
1914f9f848faSopenharmony_ci *
1915f9f848faSopenharmony_ci * This function is to be used by a bus's DEVICE_SUSPEND_CHILD().
1916f9f848faSopenharmony_ci */
1917f9f848faSopenharmony_ciint
1918f9f848faSopenharmony_cibus_generic_suspend_child(device_t dev, device_t child)
1919f9f848faSopenharmony_ci{
1920f9f848faSopenharmony_ci        int     error;
1921f9f848faSopenharmony_ci
1922f9f848faSopenharmony_ci        error = DEVICE_SUSPEND(child);
1923f9f848faSopenharmony_ci
1924f9f848faSopenharmony_ci        if (error == 0)
1925f9f848faSopenharmony_ci                child->flags |= DF_SUSPENDED;
1926f9f848faSopenharmony_ci
1927f9f848faSopenharmony_ci        return (error);
1928f9f848faSopenharmony_ci}
1929f9f848faSopenharmony_ci
1930f9f848faSopenharmony_ci/**
1931f9f848faSopenharmony_ci * @brief Default function for resuming a child device.
1932f9f848faSopenharmony_ci *
1933f9f848faSopenharmony_ci * This function is to be used by a bus's DEVICE_RESUME_CHILD().
1934f9f848faSopenharmony_ci */
1935f9f848faSopenharmony_ciint
1936f9f848faSopenharmony_cibus_generic_resume_child(device_t dev, device_t child)
1937f9f848faSopenharmony_ci{
1938f9f848faSopenharmony_ci
1939f9f848faSopenharmony_ci        DEVICE_RESUME(child);
1940f9f848faSopenharmony_ci        child->flags &= ~DF_SUSPENDED;
1941f9f848faSopenharmony_ci
1942f9f848faSopenharmony_ci        return (0);
1943f9f848faSopenharmony_ci}
1944f9f848faSopenharmony_ci
1945f9f848faSopenharmony_ci/**
1946f9f848faSopenharmony_ci * @brief Helper function for implementing DEVICE_SUSPEND()
1947f9f848faSopenharmony_ci *
1948f9f848faSopenharmony_ci * This function can be used to help implement the DEVICE_SUSPEND()
1949f9f848faSopenharmony_ci * for a bus. It calls DEVICE_SUSPEND() for each of the device's
1950f9f848faSopenharmony_ci * children. If any call to DEVICE_SUSPEND() fails, the suspend
1951f9f848faSopenharmony_ci * operation is aborted and any devices which were suspended are
1952f9f848faSopenharmony_ci * resumed immediately by calling their DEVICE_RESUME() methods.
1953f9f848faSopenharmony_ci */
1954f9f848faSopenharmony_ciint
1955f9f848faSopenharmony_cibus_generic_suspend(device_t dev)
1956f9f848faSopenharmony_ci{
1957f9f848faSopenharmony_ci        int             error;
1958f9f848faSopenharmony_ci        device_t        child;
1959f9f848faSopenharmony_ci
1960f9f848faSopenharmony_ci        /*
1961f9f848faSopenharmony_ci         * Suspend children in the reverse order.
1962f9f848faSopenharmony_ci         * For most buses all children are equal, so the order does not matter.
1963f9f848faSopenharmony_ci         * Other buses, such as acpi, carefully order their child devices to
1964f9f848faSopenharmony_ci         * express implicit dependencies between them.  For such buses it is
1965f9f848faSopenharmony_ci         * safer to bring down devices in the reverse order.
1966f9f848faSopenharmony_ci         */
1967f9f848faSopenharmony_ci        TAILQ_FOREACH_REVERSE(child, &dev->children, device_list, link) {
1968f9f848faSopenharmony_ci                error = BUS_SUSPEND_CHILD(dev, child);
1969f9f848faSopenharmony_ci                if (error != 0) {
1970f9f848faSopenharmony_ci                        child = TAILQ_NEXT(child, link);
1971f9f848faSopenharmony_ci                        if (child != NULL) {
1972f9f848faSopenharmony_ci                                TAILQ_FOREACH_FROM(child, &dev->children, link)
1973f9f848faSopenharmony_ci                                        BUS_RESUME_CHILD(dev, child);
1974f9f848faSopenharmony_ci                        }
1975f9f848faSopenharmony_ci                        return (error);
1976f9f848faSopenharmony_ci                }
1977f9f848faSopenharmony_ci        }
1978f9f848faSopenharmony_ci        return (0);
1979f9f848faSopenharmony_ci}
1980f9f848faSopenharmony_ci
1981f9f848faSopenharmony_ci/**
1982f9f848faSopenharmony_ci * @brief Helper function for implementing DEVICE_RESUME()
1983f9f848faSopenharmony_ci *
1984f9f848faSopenharmony_ci * This function can be used to help implement the DEVICE_RESUME() for
1985f9f848faSopenharmony_ci * a bus. It calls DEVICE_RESUME() on each of the device's children.
1986f9f848faSopenharmony_ci */
1987f9f848faSopenharmony_ciint
1988f9f848faSopenharmony_cibus_generic_resume(device_t dev)
1989f9f848faSopenharmony_ci{
1990f9f848faSopenharmony_ci        device_t        child;
1991f9f848faSopenharmony_ci
1992f9f848faSopenharmony_ci        TAILQ_FOREACH(child, &dev->children, link) {
1993f9f848faSopenharmony_ci                BUS_RESUME_CHILD(dev, child);
1994f9f848faSopenharmony_ci                /* if resume fails, there's nothing we can usefully do... */
1995f9f848faSopenharmony_ci        }
1996f9f848faSopenharmony_ci        return (0);
1997f9f848faSopenharmony_ci}
1998f9f848faSopenharmony_ci
1999f9f848faSopenharmony_ci
2000f9f848faSopenharmony_ci
2001f9f848faSopenharmony_ci/**
2002f9f848faSopenharmony_ci * @brief Helper function for implementing BUS_PRINT_CHILD().
2003f9f848faSopenharmony_ci *
2004f9f848faSopenharmony_ci * This function prints the first part of the ascii representation of
2005f9f848faSopenharmony_ci * @p child, including its name, unit and description (if any - see
2006f9f848faSopenharmony_ci * device_set_desc()).
2007f9f848faSopenharmony_ci *
2008f9f848faSopenharmony_ci * @returns the number of characters printed
2009f9f848faSopenharmony_ci */
2010f9f848faSopenharmony_ciint
2011f9f848faSopenharmony_cibus_print_child_header(device_t dev, device_t child)
2012f9f848faSopenharmony_ci{
2013f9f848faSopenharmony_ci        int     retval = 0;
2014f9f848faSopenharmony_ci
2015f9f848faSopenharmony_ci        if (device_get_desc(child)) {
2016f9f848faSopenharmony_ci                retval += device_printf(child, "<%s>", device_get_desc(child));
2017f9f848faSopenharmony_ci        } else {
2018f9f848faSopenharmony_ci                retval += printf("%s", device_get_nameunit(child));
2019f9f848faSopenharmony_ci        }
2020f9f848faSopenharmony_ci
2021f9f848faSopenharmony_ci        return (retval);
2022f9f848faSopenharmony_ci}
2023f9f848faSopenharmony_ci
2024f9f848faSopenharmony_ci/**
2025f9f848faSopenharmony_ci * @brief Helper function for implementing BUS_PRINT_CHILD().
2026f9f848faSopenharmony_ci *
2027f9f848faSopenharmony_ci * This function prints the last part of the ascii representation of
2028f9f848faSopenharmony_ci * @p child, which consists of the string @c " on " followed by the
2029f9f848faSopenharmony_ci * name and unit of the @p dev.
2030f9f848faSopenharmony_ci *
2031f9f848faSopenharmony_ci * @returns the number of characters printed
2032f9f848faSopenharmony_ci */
2033f9f848faSopenharmony_ciint
2034f9f848faSopenharmony_cibus_print_child_footer(device_t dev, device_t child)
2035f9f848faSopenharmony_ci{
2036f9f848faSopenharmony_ci        return (printf(" on %s\n", device_get_nameunit(dev)));
2037f9f848faSopenharmony_ci}
2038f9f848faSopenharmony_ci
2039f9f848faSopenharmony_ci/**
2040f9f848faSopenharmony_ci * @brief Helper function for implementing BUS_PRINT_CHILD().
2041f9f848faSopenharmony_ci *
2042f9f848faSopenharmony_ci * This function prints out the VM domain for the given device.
2043f9f848faSopenharmony_ci *
2044f9f848faSopenharmony_ci * @returns the number of characters printed
2045f9f848faSopenharmony_ci */
2046f9f848faSopenharmony_ciint
2047f9f848faSopenharmony_cibus_print_child_domain(device_t dev, device_t child)
2048f9f848faSopenharmony_ci{
2049f9f848faSopenharmony_ci        int domain;
2050f9f848faSopenharmony_ci
2051f9f848faSopenharmony_ci        /* No domain? Don't print anything */
2052f9f848faSopenharmony_ci        if (BUS_GET_DOMAIN(dev, child, &domain) != 0)
2053f9f848faSopenharmony_ci                return (0);
2054f9f848faSopenharmony_ci
2055f9f848faSopenharmony_ci        return (printf(" numa-domain %d", domain));
2056f9f848faSopenharmony_ci}
2057f9f848faSopenharmony_ci
2058f9f848faSopenharmony_ci/**
2059f9f848faSopenharmony_ci * @brief Helper function for implementing BUS_PRINT_CHILD().
2060f9f848faSopenharmony_ci *
2061f9f848faSopenharmony_ci * This function simply calls bus_print_child_header() followed by
2062f9f848faSopenharmony_ci * bus_print_child_footer().
2063f9f848faSopenharmony_ci *
2064f9f848faSopenharmony_ci * @returns the number of characters printed
2065f9f848faSopenharmony_ci */
2066f9f848faSopenharmony_ciint
2067f9f848faSopenharmony_cibus_generic_print_child(device_t dev, device_t child)
2068f9f848faSopenharmony_ci{
2069f9f848faSopenharmony_ci        int     retval = 0;
2070f9f848faSopenharmony_ci
2071f9f848faSopenharmony_ci        retval += bus_print_child_header(dev, child);
2072f9f848faSopenharmony_ci        retval += bus_print_child_domain(dev, child);
2073f9f848faSopenharmony_ci        retval += bus_print_child_footer(dev, child);
2074f9f848faSopenharmony_ci
2075f9f848faSopenharmony_ci        return (retval);
2076f9f848faSopenharmony_ci}
2077f9f848faSopenharmony_ci
2078f9f848faSopenharmony_ci/**
2079f9f848faSopenharmony_ci * @brief Helper function for implementing BUS_DRIVER_ADDED().
2080f9f848faSopenharmony_ci *
2081f9f848faSopenharmony_ci * This implementation of BUS_DRIVER_ADDED() simply calls the driver's
2082f9f848faSopenharmony_ci * DEVICE_IDENTIFY() method to allow it to add new children to the bus
2083f9f848faSopenharmony_ci * and then calls device_probe_and_attach() for each unattached child.
2084f9f848faSopenharmony_ci */
2085f9f848faSopenharmony_civoid
2086f9f848faSopenharmony_cibus_generic_driver_added(device_t dev, driver_t *driver)
2087f9f848faSopenharmony_ci{
2088f9f848faSopenharmony_ci        device_t child;
2089f9f848faSopenharmony_ci        PDEBUG(("+"));
2090f9f848faSopenharmony_ci
2091f9f848faSopenharmony_ci        DEVICE_IDENTIFY(driver, dev);
2092f9f848faSopenharmony_ci        PDEBUG(("dev->children %p", dev->children));
2093f9f848faSopenharmony_ci        TAILQ_FOREACH(child, &dev->children, link) {
2094f9f848faSopenharmony_ci                if (child->state == DS_NOTPRESENT ||
2095f9f848faSopenharmony_ci                    (child->flags & DF_REBID))
2096f9f848faSopenharmony_ci                        device_probe_and_attach(child);
2097f9f848faSopenharmony_ci        }
2098f9f848faSopenharmony_ci        PDEBUG(("-"));
2099f9f848faSopenharmony_ci}
2100f9f848faSopenharmony_ci
2101f9f848faSopenharmony_ci/**
2102f9f848faSopenharmony_ci * @brief Helper function for implementing BUS_NEW_PASS().
2103f9f848faSopenharmony_ci *
2104f9f848faSopenharmony_ci * This implementing of BUS_NEW_PASS() first calls the identify
2105f9f848faSopenharmony_ci * routines for any drivers that probe at the current pass.  Then it
2106f9f848faSopenharmony_ci * walks the list of devices for this bus.  If a device is already
2107f9f848faSopenharmony_ci * attached, then it calls BUS_NEW_PASS() on that device.  If the
2108f9f848faSopenharmony_ci * device is not already attached, it attempts to attach a driver to
2109f9f848faSopenharmony_ci * it.
2110f9f848faSopenharmony_ci */
2111f9f848faSopenharmony_civoid
2112f9f848faSopenharmony_cibus_generic_new_pass(device_t dev)
2113f9f848faSopenharmony_ci{
2114f9f848faSopenharmony_ci        driverlink_t dl = NULL;
2115f9f848faSopenharmony_ci        devclass_t dc;
2116f9f848faSopenharmony_ci        device_t child;
2117f9f848faSopenharmony_ci
2118f9f848faSopenharmony_ci        dc = dev->devclass;
2119f9f848faSopenharmony_ci        TAILQ_FOREACH(dl, &dc->drivers, link) {
2120f9f848faSopenharmony_ci                if (dl->pass == bus_current_pass)
2121f9f848faSopenharmony_ci                        DEVICE_IDENTIFY(dl->driver, dev);
2122f9f848faSopenharmony_ci        }
2123f9f848faSopenharmony_ci        TAILQ_FOREACH(child, &dev->children, link) {
2124f9f848faSopenharmony_ci                if (child->state >= DS_ATTACHED)
2125f9f848faSopenharmony_ci                        BUS_NEW_PASS(child);
2126f9f848faSopenharmony_ci                else if (child->state == DS_NOTPRESENT)
2127f9f848faSopenharmony_ci                        device_probe_and_attach(child);
2128f9f848faSopenharmony_ci        }
2129f9f848faSopenharmony_ci}
2130f9f848faSopenharmony_ci
2131f9f848faSopenharmony_ci// delete resouce and intr
2132f9f848faSopenharmony_ci
2133f9f848faSopenharmony_ci/**
2134f9f848faSopenharmony_ci * @brief Helper function for implementing BUS_CHILD_PRESENT().
2135f9f848faSopenharmony_ci *
2136f9f848faSopenharmony_ci * This simple implementation of BUS_CHILD_PRESENT() simply calls the
2137f9f848faSopenharmony_ci * BUS_CHILD_PRESENT() method of the parent of @p dev.
2138f9f848faSopenharmony_ci */
2139f9f848faSopenharmony_ciint
2140f9f848faSopenharmony_cibus_generic_child_present(device_t dev, device_t child)
2141f9f848faSopenharmony_ci{
2142f9f848faSopenharmony_ci        return (BUS_CHILD_PRESENT(device_get_parent(dev), dev));
2143f9f848faSopenharmony_ci}
2144f9f848faSopenharmony_ci
2145f9f848faSopenharmony_ciint
2146f9f848faSopenharmony_cibus_generic_get_domain(device_t dev, device_t child, int *domain)
2147f9f848faSopenharmony_ci{
2148f9f848faSopenharmony_ci
2149f9f848faSopenharmony_ci        if (dev->parent)
2150f9f848faSopenharmony_ci                return (BUS_GET_DOMAIN(dev->parent, dev, domain));
2151f9f848faSopenharmony_ci
2152f9f848faSopenharmony_ci        return (ENOENT);
2153f9f848faSopenharmony_ci}
2154f9f848faSopenharmony_ci
2155f9f848faSopenharmony_ci/**
2156f9f848faSopenharmony_ci * @brief Helper function for implementing BUS_RESCAN().
2157f9f848faSopenharmony_ci *
2158f9f848faSopenharmony_ci * This null implementation of BUS_RESCAN() always fails to indicate
2159f9f848faSopenharmony_ci * the bus does not support rescanning.
2160f9f848faSopenharmony_ci */
2161f9f848faSopenharmony_ciint
2162f9f848faSopenharmony_cibus_null_rescan(device_t dev)
2163f9f848faSopenharmony_ci{
2164f9f848faSopenharmony_ci
2165f9f848faSopenharmony_ci        return (ENXIO);
2166f9f848faSopenharmony_ci}
2167f9f848faSopenharmony_ci
2168f9f848faSopenharmony_ci/**
2169f9f848faSopenharmony_ci * @brief Wrapper function for BUS_CHILD_PRESENT().
2170f9f848faSopenharmony_ci *
2171f9f848faSopenharmony_ci * This function simply calls the BUS_CHILD_PRESENT() method of the
2172f9f848faSopenharmony_ci * parent of @p dev.
2173f9f848faSopenharmony_ci */
2174f9f848faSopenharmony_ciint
2175f9f848faSopenharmony_cibus_child_present(device_t child)
2176f9f848faSopenharmony_ci{
2177f9f848faSopenharmony_ci        return (BUS_CHILD_PRESENT(device_get_parent(child), child));
2178f9f848faSopenharmony_ci}
2179f9f848faSopenharmony_ci
2180f9f848faSopenharmony_ci/**
2181f9f848faSopenharmony_ci * @brief Wrapper function for BUS_GET_DOMAIN().
2182f9f848faSopenharmony_ci *
2183f9f848faSopenharmony_ci * This function simply calls the BUS_GET_DOMAIN() method of the
2184f9f848faSopenharmony_ci * parent of @p dev.
2185f9f848faSopenharmony_ci */
2186f9f848faSopenharmony_ciint
2187f9f848faSopenharmony_cibus_get_domain(device_t dev, int *domain)
2188f9f848faSopenharmony_ci{
2189f9f848faSopenharmony_ci        return (BUS_GET_DOMAIN(device_get_parent(dev), dev, domain));
2190f9f848faSopenharmony_ci}
2191f9f848faSopenharmony_ci
2192f9f848faSopenharmony_ciint
2193f9f848faSopenharmony_cibus_data_generation_check(int generation)
2194f9f848faSopenharmony_ci{
2195f9f848faSopenharmony_ci	if (generation != bus_data_generation)
2196f9f848faSopenharmony_ci	return (1);
2197f9f848faSopenharmony_ci
2198f9f848faSopenharmony_ci	/* XXX generate optimised lists here? */
2199f9f848faSopenharmony_ci	return (0);
2200f9f848faSopenharmony_ci}
2201f9f848faSopenharmony_ci
2202f9f848faSopenharmony_civoid
2203f9f848faSopenharmony_cibus_data_generation_update(void)
2204f9f848faSopenharmony_ci{
2205f9f848faSopenharmony_ci	bus_data_generation++;
2206f9f848faSopenharmony_ci}
2207f9f848faSopenharmony_ci
2208f9f848faSopenharmony_ci/**
2209f9f848faSopenharmony_ci * @brief Print the name of the device followed by a colon and a space
2210f9f848faSopenharmony_ci *
2211f9f848faSopenharmony_ci * @returns the number of characters printed
2212f9f848faSopenharmony_ci */
2213f9f848faSopenharmony_ciint
2214f9f848faSopenharmony_cidevice_print_prettyname(device_t dev)
2215f9f848faSopenharmony_ci{
2216f9f848faSopenharmony_ci	const char *name = device_get_name(dev);
2217f9f848faSopenharmony_ci
2218f9f848faSopenharmony_ci	if (name == NULL)
2219f9f848faSopenharmony_ci		return (printf("unknown: "));
2220f9f848faSopenharmony_ci	return (printf("%s%d: ", name, device_get_unit(dev)));
2221f9f848faSopenharmony_ci}
2222f9f848faSopenharmony_ci
2223f9f848faSopenharmony_ci/**
2224f9f848faSopenharmony_ci * @brief Return the device's unit number.
2225f9f848faSopenharmony_ci */
2226f9f848faSopenharmony_ciint
2227f9f848faSopenharmony_cidevice_get_unit(device_t dev)
2228f9f848faSopenharmony_ci{
2229f9f848faSopenharmony_ci	return (dev->unit);
2230f9f848faSopenharmony_ci}
2231f9f848faSopenharmony_ci
2232f9f848faSopenharmony_ci/**
2233f9f848faSopenharmony_ci * @internal
2234f9f848faSopenharmony_ci */
2235f9f848faSopenharmony_cistatic driverlink_t
2236f9f848faSopenharmony_cifirst_matching_driver(devclass_t dc, device_t dev)
2237f9f848faSopenharmony_ci{
2238f9f848faSopenharmony_ci	if (dev->devclass)
2239f9f848faSopenharmony_ci		return (devclass_find_driver_internal(dc, dev->devclass->name));
2240f9f848faSopenharmony_ci	return (TAILQ_FIRST(&dc->drivers));
2241f9f848faSopenharmony_ci}
2242f9f848faSopenharmony_ci
2243f9f848faSopenharmony_ci/**
2244f9f848faSopenharmony_ci * @internal
2245f9f848faSopenharmony_ci */
2246f9f848faSopenharmony_cistatic driverlink_t
2247f9f848faSopenharmony_cinext_matching_driver(devclass_t dc, device_t dev, driverlink_t last)
2248f9f848faSopenharmony_ci{
2249f9f848faSopenharmony_ci	if (dev->devclass) {
2250f9f848faSopenharmony_ci		driverlink_t dl;
2251f9f848faSopenharmony_ci		for (dl = TAILQ_NEXT(last, link); dl; dl = TAILQ_NEXT(dl, link))
2252f9f848faSopenharmony_ci			if (!strcmp(dev->devclass->name, dl->driver->name))
2253f9f848faSopenharmony_ci				return (dl);
2254f9f848faSopenharmony_ci		return (NULL);
2255f9f848faSopenharmony_ci	}
2256f9f848faSopenharmony_ci	return (TAILQ_NEXT(last, link));
2257f9f848faSopenharmony_ci}
2258f9f848faSopenharmony_ci
2259f9f848faSopenharmony_ci
2260f9f848faSopenharmony_ci/**
2261f9f848faSopenharmony_ci * @brief Set the devclass of a device
2262f9f848faSopenharmony_ci * @see devclass_add_device().
2263f9f848faSopenharmony_ci */
2264f9f848faSopenharmony_ciint
2265f9f848faSopenharmony_cidevice_set_devclass(device_t dev, const char *classname)
2266f9f848faSopenharmony_ci{
2267f9f848faSopenharmony_ci	devclass_t dc;
2268f9f848faSopenharmony_ci	int error;
2269f9f848faSopenharmony_ci
2270f9f848faSopenharmony_ci	if (!classname) {
2271f9f848faSopenharmony_ci		if (dev->devclass)
2272f9f848faSopenharmony_ci			devclass_delete_device(dev->devclass, dev);
2273f9f848faSopenharmony_ci		return (0);
2274f9f848faSopenharmony_ci	}
2275f9f848faSopenharmony_ci
2276f9f848faSopenharmony_ci	if (dev->devclass) {
2277f9f848faSopenharmony_ci		printf("device_set_devclass: device class already set\n");
2278f9f848faSopenharmony_ci		return (EINVAL);
2279f9f848faSopenharmony_ci	}
2280f9f848faSopenharmony_ci
2281f9f848faSopenharmony_ci	dc = devclass_find_internal(classname, NULL, TRUE);
2282f9f848faSopenharmony_ci	if (!dc)
2283f9f848faSopenharmony_ci		return (ENOMEM);
2284f9f848faSopenharmony_ci
2285f9f848faSopenharmony_ci	error = devclass_add_device(dc, dev);
2286f9f848faSopenharmony_ci
2287f9f848faSopenharmony_ci	bus_data_generation_update();
2288f9f848faSopenharmony_ci	return (error);
2289f9f848faSopenharmony_ci}
2290f9f848faSopenharmony_ci
2291f9f848faSopenharmony_ci/**
2292f9f848faSopenharmony_ci * @brief Detach a driver from a device
2293f9f848faSopenharmony_ci *
2294f9f848faSopenharmony_ci * This function is a wrapper around the DEVICE_DETACH() driver
2295f9f848faSopenharmony_ci * method. If the call to DEVICE_DETACH() succeeds, it calls
2296f9f848faSopenharmony_ci * BUS_CHILD_DETACHED() for the parent of @p dev, queues a
2297f9f848faSopenharmony_ci * notification event for user-based device management services and
2298f9f848faSopenharmony_ci * cleans up the device's sysctl tree.
2299f9f848faSopenharmony_ci *
2300f9f848faSopenharmony_ci * @param dev		the device to un-initialise
2301f9f848faSopenharmony_ci *
2302f9f848faSopenharmony_ci * @retval 0		success
2303f9f848faSopenharmony_ci * @retval ENXIO	no driver was found
2304f9f848faSopenharmony_ci * @retval ENOMEM	memory allocation failure
2305f9f848faSopenharmony_ci * @retval non-zero	some other unix error code
2306f9f848faSopenharmony_ci */
2307f9f848faSopenharmony_ciint
2308f9f848faSopenharmony_cidevice_detach(device_t dev)
2309f9f848faSopenharmony_ci{
2310f9f848faSopenharmony_ci	int error;
2311f9f848faSopenharmony_ci
2312f9f848faSopenharmony_ci	GIANT_REQUIRED;
2313f9f848faSopenharmony_ci
2314f9f848faSopenharmony_ci	PDEBUG(("%s", DEVICENAME(dev)));
2315f9f848faSopenharmony_ci	if (dev->state == DS_BUSY)
2316f9f848faSopenharmony_ci		return (EBUSY);
2317f9f848faSopenharmony_ci	if (dev->state == DS_ATTACHING) {
2318f9f848faSopenharmony_ci		device_printf(dev, "device in attaching state! Deferring detach.\n");
2319f9f848faSopenharmony_ci		return (EBUSY);
2320f9f848faSopenharmony_ci	}
2321f9f848faSopenharmony_ci	if (dev->state != DS_ATTACHED)
2322f9f848faSopenharmony_ci		return (0);
2323f9f848faSopenharmony_ci
2324f9f848faSopenharmony_ci	if ((error = DEVICE_DETACH(dev)) != 0) {
2325f9f848faSopenharmony_ci		return (error);
2326f9f848faSopenharmony_ci	}
2327f9f848faSopenharmony_ci
2328f9f848faSopenharmony_ci	if (!device_is_quiet(dev))
2329f9f848faSopenharmony_ci		device_printf(dev, "detached\n");
2330f9f848faSopenharmony_ci	if (dev->parent) {
2331f9f848faSopenharmony_ci		PDEBUG(("BUS_CHILD_DETACHED %s", DEVICENAME(dev->parent)));
2332f9f848faSopenharmony_ci		BUS_CHILD_DETACHED(dev->parent, dev);
2333f9f848faSopenharmony_ci	}
2334f9f848faSopenharmony_ci
2335f9f848faSopenharmony_ci	if (!(dev->flags & DF_FIXEDCLASS)) {
2336f9f848faSopenharmony_ci		PDEBUG(("devclass_delete_device"));
2337f9f848faSopenharmony_ci		devclass_delete_device(dev->devclass, dev);
2338f9f848faSopenharmony_ci	}
2339f9f848faSopenharmony_ci
2340f9f848faSopenharmony_ci	device_verbose(dev);
2341f9f848faSopenharmony_ci	dev->state = DS_NOTPRESENT;
2342f9f848faSopenharmony_ci	(void)device_set_driver(dev, NULL);
2343f9f848faSopenharmony_ci
2344f9f848faSopenharmony_ci	return (0);
2345f9f848faSopenharmony_ci}
2346f9f848faSopenharmony_ci
2347f9f848faSopenharmony_ci/**
2348f9f848faSopenharmony_ci * @brief Return the parent of a device
2349f9f848faSopenharmony_ci */
2350f9f848faSopenharmony_cidevice_t
2351f9f848faSopenharmony_cidevice_get_parent(device_t dev)
2352f9f848faSopenharmony_ci{
2353f9f848faSopenharmony_ci	return (dev->parent);
2354f9f848faSopenharmony_ci}
2355f9f848faSopenharmony_ci
2356f9f848faSopenharmony_ci/**
2357f9f848faSopenharmony_ci * @brief Print the name of the device followed by a colon, a space
2358f9f848faSopenharmony_ci * and the result of calling vprintf() with the value of @p fmt and
2359f9f848faSopenharmony_ci * the following arguments.
2360f9f848faSopenharmony_ci *
2361f9f848faSopenharmony_ci * @returns the number of characters printed
2362f9f848faSopenharmony_ci */
2363f9f848faSopenharmony_ciint
2364f9f848faSopenharmony_cidevice_printf(device_t dev, const char * fmt, ...)
2365f9f848faSopenharmony_ci{
2366f9f848faSopenharmony_ci	va_list ap;
2367f9f848faSopenharmony_ci	int retval;
2368f9f848faSopenharmony_ci
2369f9f848faSopenharmony_ci	retval = device_print_prettyname(dev);
2370f9f848faSopenharmony_ci	va_start(ap, fmt);
2371f9f848faSopenharmony_ci	retval += vprintf(fmt, ap);
2372f9f848faSopenharmony_ci	va_end(ap);
2373f9f848faSopenharmony_ci	return (retval);
2374f9f848faSopenharmony_ci}
2375f9f848faSopenharmony_ci
2376f9f848faSopenharmony_ci/**
2377f9f848faSopenharmony_ci * @brief Set the driver of a device
2378f9f848faSopenharmony_ci *
2379f9f848faSopenharmony_ci * @retval 0		success
2380f9f848faSopenharmony_ci * @retval EBUSY	the device already has a driver attached
2381f9f848faSopenharmony_ci * @retval ENOMEM	a memory allocation failure occurred
2382f9f848faSopenharmony_ci */
2383f9f848faSopenharmony_ciint
2384f9f848faSopenharmony_cidevice_set_driver(device_t dev, driver_t *driver)
2385f9f848faSopenharmony_ci{
2386f9f848faSopenharmony_ci	if (dev->state >= DS_ATTACHED)
2387f9f848faSopenharmony_ci		return (EBUSY);
2388f9f848faSopenharmony_ci
2389f9f848faSopenharmony_ci	if (dev->driver == driver)
2390f9f848faSopenharmony_ci		return (0);
2391f9f848faSopenharmony_ci
2392f9f848faSopenharmony_ci	if (dev->softc && !(dev->flags & DF_EXTERNALSOFTC)) {
2393f9f848faSopenharmony_ci		bsd_free(dev->softc, M_BUS_SC);
2394f9f848faSopenharmony_ci		dev->softc = NULL;
2395f9f848faSopenharmony_ci	}
2396f9f848faSopenharmony_ci	device_set_desc(dev, NULL);
2397f9f848faSopenharmony_ci	kobj_delete((kobj_t) dev, NULL);
2398f9f848faSopenharmony_ci	dev->driver = driver;
2399f9f848faSopenharmony_ci	if (driver) {
2400f9f848faSopenharmony_ci		kobj_init((kobj_t) dev, (kobj_class_t) driver);
2401f9f848faSopenharmony_ci		if (!(dev->flags & DF_EXTERNALSOFTC) && driver->size > 0) {
2402f9f848faSopenharmony_ci			dev->softc = bsd_malloc(driver->size, M_BUS_SC,
2403f9f848faSopenharmony_ci			    M_NOWAIT | M_ZERO);
2404f9f848faSopenharmony_ci			if (!dev->softc) {
2405f9f848faSopenharmony_ci				kobj_delete((kobj_t) dev, NULL);
2406f9f848faSopenharmony_ci				kobj_init((kobj_t) dev, &null_class);
2407f9f848faSopenharmony_ci				dev->driver = NULL;
2408f9f848faSopenharmony_ci				return (ENOMEM);
2409f9f848faSopenharmony_ci			}
2410f9f848faSopenharmony_ci		}
2411f9f848faSopenharmony_ci	} else {
2412f9f848faSopenharmony_ci		kobj_init((kobj_t) dev, &null_class);
2413f9f848faSopenharmony_ci	}
2414f9f848faSopenharmony_ci
2415f9f848faSopenharmony_ci	bus_data_generation_update();
2416f9f848faSopenharmony_ci	return (0);
2417f9f848faSopenharmony_ci}
2418f9f848faSopenharmony_ci
2419f9f848faSopenharmony_ci/**
2420f9f848faSopenharmony_ci * @internal
2421f9f848faSopenharmony_ci */
2422f9f848faSopenharmony_ciint
2423f9f848faSopenharmony_cidevice_probe_child(device_t dev, device_t child)
2424f9f848faSopenharmony_ci{
2425f9f848faSopenharmony_ci	devclass_t dc;
2426f9f848faSopenharmony_ci	driverlink_t best = NULL;
2427f9f848faSopenharmony_ci	driverlink_t dl = NULL;
2428f9f848faSopenharmony_ci	int result, pri = 0;
2429f9f848faSopenharmony_ci	int hasclass = (child->devclass != NULL);
2430f9f848faSopenharmony_ci
2431f9f848faSopenharmony_ci	GIANT_REQUIRED;
2432f9f848faSopenharmony_ci
2433f9f848faSopenharmony_ci	dc = dev->devclass;
2434f9f848faSopenharmony_ci	if (!dc)
2435f9f848faSopenharmony_ci		panic("device_probe_child: parent device has no devclass");
2436f9f848faSopenharmony_ci
2437f9f848faSopenharmony_ci	/*
2438f9f848faSopenharmony_ci	 * If the state is already probed, then return.  However, don't
2439f9f848faSopenharmony_ci	 * return if we can rebid this object.
2440f9f848faSopenharmony_ci	 */
2441f9f848faSopenharmony_ci	if (child->state == DS_ALIVE && (child->flags & DF_REBID) == 0)
2442f9f848faSopenharmony_ci		return (0);
2443f9f848faSopenharmony_ci
2444f9f848faSopenharmony_ci	for (; dc; dc = dc->parent) {
2445f9f848faSopenharmony_ci		for (dl = first_matching_driver(dc, child);
2446f9f848faSopenharmony_ci		     dl;
2447f9f848faSopenharmony_ci		     dl = next_matching_driver(dc, child, dl)) {
2448f9f848faSopenharmony_ci			/* If this driver's pass is too high, then ignore it. */
2449f9f848faSopenharmony_ci			if (dl->pass > bus_current_pass)
2450f9f848faSopenharmony_ci				continue;
2451f9f848faSopenharmony_ci
2452f9f848faSopenharmony_ci			PDEBUG(("Trying %s", DRIVERNAME(dl->driver)));
2453f9f848faSopenharmony_ci			result = device_set_driver(child, dl->driver);
2454f9f848faSopenharmony_ci			if (result == ENOMEM)
2455f9f848faSopenharmony_ci				return (result);
2456f9f848faSopenharmony_ci			else if (result != 0)
2457f9f848faSopenharmony_ci				continue;
2458f9f848faSopenharmony_ci			if (!hasclass) {
2459f9f848faSopenharmony_ci				if (device_set_devclass(child,
2460f9f848faSopenharmony_ci				    dl->driver->name) != 0) {
2461f9f848faSopenharmony_ci					char const * devname =
2462f9f848faSopenharmony_ci					    device_get_name(child);
2463f9f848faSopenharmony_ci					if (devname == NULL)
2464f9f848faSopenharmony_ci						devname = "(unknown)";
2465f9f848faSopenharmony_ci					printf("driver bug: Unable to set "
2466f9f848faSopenharmony_ci					    "devclass (class: %s "
2467f9f848faSopenharmony_ci					    "devname: %s)\n",
2468f9f848faSopenharmony_ci					    dl->driver->name,
2469f9f848faSopenharmony_ci					    devname);
2470f9f848faSopenharmony_ci					(void)device_set_driver(child, NULL);
2471f9f848faSopenharmony_ci					continue;
2472f9f848faSopenharmony_ci				}
2473f9f848faSopenharmony_ci			}
2474f9f848faSopenharmony_ci
2475f9f848faSopenharmony_ci			/* Fetch any flags for the device before probing. */
2476f9f848faSopenharmony_ci			// resource_int_value(dl->driver->name, child->unit,
2477f9f848faSopenharmony_ci			    // "flags", &child->devflags);
2478f9f848faSopenharmony_ci                        PDEBUG(("start DEVICE_PROBE"));
2479f9f848faSopenharmony_ci			result = DEVICE_PROBE(child);
2480f9f848faSopenharmony_ci
2481f9f848faSopenharmony_ci			/* Reset flags and devclass before the next probe. */
2482f9f848faSopenharmony_ci			child->devflags = 0;
2483f9f848faSopenharmony_ci			if (!hasclass)
2484f9f848faSopenharmony_ci				(void)device_set_devclass(child, NULL);
2485f9f848faSopenharmony_ci
2486f9f848faSopenharmony_ci			/*
2487f9f848faSopenharmony_ci			 * If the driver returns SUCCESS, there can be
2488f9f848faSopenharmony_ci			 * no higher match for this device.
2489f9f848faSopenharmony_ci			 */
2490f9f848faSopenharmony_ci			if (result == 0) {
2491f9f848faSopenharmony_ci				best = dl;
2492f9f848faSopenharmony_ci				pri = 0;
2493f9f848faSopenharmony_ci				break;
2494f9f848faSopenharmony_ci			}
2495f9f848faSopenharmony_ci
2496f9f848faSopenharmony_ci			/*
2497f9f848faSopenharmony_ci			 * Reset DF_QUIET in case this driver doesn't
2498f9f848faSopenharmony_ci			 * end up as the best driver.
2499f9f848faSopenharmony_ci			 */
2500f9f848faSopenharmony_ci			device_verbose(child);
2501f9f848faSopenharmony_ci
2502f9f848faSopenharmony_ci                        PDEBUG(("probe result: %d", result));
2503f9f848faSopenharmony_ci			/*
2504f9f848faSopenharmony_ci			 * Probes that return BUS_PROBE_NOWILDCARD or lower
2505f9f848faSopenharmony_ci			 * only match on devices whose driver was explicitly
2506f9f848faSopenharmony_ci			 * specified.
2507f9f848faSopenharmony_ci			 */
2508f9f848faSopenharmony_ci			if (result <= BUS_PROBE_NOWILDCARD &&
2509f9f848faSopenharmony_ci			    !(child->flags & DF_FIXEDCLASS)) {
2510f9f848faSopenharmony_ci				result = ENXIO;
2511f9f848faSopenharmony_ci			}
2512f9f848faSopenharmony_ci
2513f9f848faSopenharmony_ci			/*
2514f9f848faSopenharmony_ci			 * The driver returned an error so it
2515f9f848faSopenharmony_ci			 * certainly doesn't match.
2516f9f848faSopenharmony_ci			 */
2517f9f848faSopenharmony_ci			if (result > 0) {
2518f9f848faSopenharmony_ci				(void)device_set_driver(child, NULL);
2519f9f848faSopenharmony_ci				continue;
2520f9f848faSopenharmony_ci			}
2521f9f848faSopenharmony_ci
2522f9f848faSopenharmony_ci			/*
2523f9f848faSopenharmony_ci			 * A priority lower than SUCCESS, remember the
2524f9f848faSopenharmony_ci			 * best matching driver. Initialise the value
2525f9f848faSopenharmony_ci			 * of pri for the first match.
2526f9f848faSopenharmony_ci			 */
2527f9f848faSopenharmony_ci			if (best == NULL || result > pri) {
2528f9f848faSopenharmony_ci				best = dl;
2529f9f848faSopenharmony_ci				pri = result;
2530f9f848faSopenharmony_ci				continue;
2531f9f848faSopenharmony_ci			}
2532f9f848faSopenharmony_ci		}
2533f9f848faSopenharmony_ci		/*
2534f9f848faSopenharmony_ci		 * If we have an unambiguous match in this devclass,
2535f9f848faSopenharmony_ci		 * don't look in the parent.
2536f9f848faSopenharmony_ci		 */
2537f9f848faSopenharmony_ci		if (best && pri == 0)
2538f9f848faSopenharmony_ci			break;
2539f9f848faSopenharmony_ci	}
2540f9f848faSopenharmony_ci
2541f9f848faSopenharmony_ci	/*
2542f9f848faSopenharmony_ci	 * If we found a driver, change state and initialise the devclass.
2543f9f848faSopenharmony_ci	 */
2544f9f848faSopenharmony_ci	/* XXX What happens if we rebid and got no best? */
2545f9f848faSopenharmony_ci	if (best) {
2546f9f848faSopenharmony_ci                PDEBUG(("in best"));
2547f9f848faSopenharmony_ci		/*
2548f9f848faSopenharmony_ci		 * If this device was attached, and we were asked to
2549f9f848faSopenharmony_ci		 * rescan, and it is a different driver, then we have
2550f9f848faSopenharmony_ci		 * to detach the old driver and reattach this new one.
2551f9f848faSopenharmony_ci		 * Note, we don't have to check for DF_REBID here
2552f9f848faSopenharmony_ci		 * because if the state is > DS_ALIVE, we know it must
2553f9f848faSopenharmony_ci		 * be.
2554f9f848faSopenharmony_ci		 *
2555f9f848faSopenharmony_ci		 * This assumes that all DF_REBID drivers can have
2556f9f848faSopenharmony_ci		 * their probe routine called at any time and that
2557f9f848faSopenharmony_ci		 * they are idempotent as well as completely benign in
2558f9f848faSopenharmony_ci		 * normal operations.
2559f9f848faSopenharmony_ci		 *
2560f9f848faSopenharmony_ci		 * We also have to make sure that the detach
2561f9f848faSopenharmony_ci		 * succeeded, otherwise we fail the operation (or
2562f9f848faSopenharmony_ci		 * maybe it should just fail silently?  I'm torn).
2563f9f848faSopenharmony_ci		 */
2564f9f848faSopenharmony_ci		if (child->state > DS_ALIVE && best->driver != child->driver)
2565f9f848faSopenharmony_ci			if ((result = device_detach(dev)) != 0)
2566f9f848faSopenharmony_ci				return (result);
2567f9f848faSopenharmony_ci
2568f9f848faSopenharmony_ci		/* Set the winning driver, devclass, and flags. */
2569f9f848faSopenharmony_ci		if (!child->devclass) {
2570f9f848faSopenharmony_ci			result = device_set_devclass(child, best->driver->name);
2571f9f848faSopenharmony_ci			if (result != 0)
2572f9f848faSopenharmony_ci				return (result);
2573f9f848faSopenharmony_ci		}
2574f9f848faSopenharmony_ci		result = device_set_driver(child, best->driver);
2575f9f848faSopenharmony_ci		if (result != 0)
2576f9f848faSopenharmony_ci			return (result);
2577f9f848faSopenharmony_ci		// resource_int_value(best->driver->name, child->unit,
2578f9f848faSopenharmony_ci		    // "flags", &child->devflags);
2579f9f848faSopenharmony_ci
2580f9f848faSopenharmony_ci		if (pri < 0) {
2581f9f848faSopenharmony_ci			/*
2582f9f848faSopenharmony_ci			 * A bit bogus. Call the probe method again to make
2583f9f848faSopenharmony_ci			 * sure that we have the right description.
2584f9f848faSopenharmony_ci			 */
2585f9f848faSopenharmony_ci			DEVICE_PROBE(child);
2586f9f848faSopenharmony_ci#if 0
2587f9f848faSopenharmony_ci			child->flags |= DF_REBID;
2588f9f848faSopenharmony_ci#endif
2589f9f848faSopenharmony_ci		} else
2590f9f848faSopenharmony_ci			child->flags &= ~DF_REBID;
2591f9f848faSopenharmony_ci		child->state = DS_ALIVE;
2592f9f848faSopenharmony_ci
2593f9f848faSopenharmony_ci		bus_data_generation_update();
2594f9f848faSopenharmony_ci                PDEBUG(("-"));
2595f9f848faSopenharmony_ci		return (0);
2596f9f848faSopenharmony_ci	}
2597f9f848faSopenharmony_ci
2598f9f848faSopenharmony_ci        PDEBUG(("ENXIO -"));
2599f9f848faSopenharmony_ci	return (ENXIO);
2600f9f848faSopenharmony_ci}
2601f9f848faSopenharmony_ci
2602f9f848faSopenharmony_ci
2603f9f848faSopenharmony_ci/**
2604f9f848faSopenharmony_ci * @brief Return the current devclass for the device or @c NULL if
2605f9f848faSopenharmony_ci * there is none.
2606f9f848faSopenharmony_ci */
2607f9f848faSopenharmony_cidevclass_t
2608f9f848faSopenharmony_cidevice_get_devclass(device_t dev)
2609f9f848faSopenharmony_ci{
2610f9f848faSopenharmony_ci	return (dev->devclass);
2611f9f848faSopenharmony_ci}
2612f9f848faSopenharmony_ci
2613f9f848faSopenharmony_ci/**
2614f9f848faSopenharmony_ci * @brief Initialise a resource list.
2615f9f848faSopenharmony_ci *
2616f9f848faSopenharmony_ci * @param rl		the resource list to initialise
2617f9f848faSopenharmony_ci */
2618f9f848faSopenharmony_civoid
2619f9f848faSopenharmony_ciresource_list_init(struct resource_list *rl)
2620f9f848faSopenharmony_ci{
2621f9f848faSopenharmony_ci	STAILQ_INIT(rl);
2622f9f848faSopenharmony_ci}
2623f9f848faSopenharmony_ci
2624f9f848faSopenharmony_ci/**
2625f9f848faSopenharmony_ci * @brief Reclaim memory used by a resource list.
2626f9f848faSopenharmony_ci *
2627f9f848faSopenharmony_ci * This function frees the memory for all resource entries on the list
2628f9f848faSopenharmony_ci * (if any).
2629f9f848faSopenharmony_ci *
2630f9f848faSopenharmony_ci * @param rl		the resource list to free
2631f9f848faSopenharmony_ci */
2632f9f848faSopenharmony_civoid
2633f9f848faSopenharmony_ciresource_list_free(struct resource_list *rl)
2634f9f848faSopenharmony_ci{
2635f9f848faSopenharmony_ci	struct resource_list_entry *rle;
2636f9f848faSopenharmony_ci
2637f9f848faSopenharmony_ci	while ((rle = STAILQ_FIRST(rl)) != NULL) {
2638f9f848faSopenharmony_ci		if (rle->res)
2639f9f848faSopenharmony_ci			bsd_free(rle->res, M_BUS);
2640f9f848faSopenharmony_ci		STAILQ_REMOVE_HEAD(rl, link);
2641f9f848faSopenharmony_ci		bsd_free(rle, M_BUS);
2642f9f848faSopenharmony_ci	}
2643f9f848faSopenharmony_ci}
2644f9f848faSopenharmony_ci
2645f9f848faSopenharmony_ci/**
2646f9f848faSopenharmony_ci * @brief Add or modify a resource entry.
2647f9f848faSopenharmony_ci *
2648f9f848faSopenharmony_ci * If an existing entry exists with the same type and rid, it will be
2649f9f848faSopenharmony_ci * modified using the given values of @p start, @p end and @p
2650f9f848faSopenharmony_ci * count. If no entry exists, a new one will be created using the
2651f9f848faSopenharmony_ci * given values.  The resource list entry that matches is then returned.
2652f9f848faSopenharmony_ci *
2653f9f848faSopenharmony_ci * @param rl		the resource list to edit
2654f9f848faSopenharmony_ci * @param type		the resource entry type (e.g. SYS_RES_MEMORY)
2655f9f848faSopenharmony_ci * @param rid		the resource identifier
2656f9f848faSopenharmony_ci * @param start		the start address of the resource
2657f9f848faSopenharmony_ci * @param end		the end address of the resource
2658f9f848faSopenharmony_ci * @param count		XXX end-start+1
2659f9f848faSopenharmony_ci */
2660f9f848faSopenharmony_cistruct resource_list_entry *
2661f9f848faSopenharmony_ciresource_list_add(struct resource_list *rl, int type, int rid,
2662f9f848faSopenharmony_ci    rman_res_t start, rman_res_t end, rman_res_t count)
2663f9f848faSopenharmony_ci{
2664f9f848faSopenharmony_ci	struct resource_list_entry *rle;
2665f9f848faSopenharmony_ci
2666f9f848faSopenharmony_ci	rle = resource_list_find(rl, type, rid);
2667f9f848faSopenharmony_ci	if (!rle) {
2668f9f848faSopenharmony_ci		rle = bsd_malloc(sizeof(struct resource_list_entry), M_BUS,
2669f9f848faSopenharmony_ci		    M_NOWAIT);
2670f9f848faSopenharmony_ci		if (!rle)
2671f9f848faSopenharmony_ci			panic("resource_list_add: can't record entry");
2672f9f848faSopenharmony_ci		STAILQ_INSERT_TAIL(rl, rle, link);
2673f9f848faSopenharmony_ci		rle->type = type;
2674f9f848faSopenharmony_ci		rle->rid = rid;
2675f9f848faSopenharmony_ci		rle->res = NULL;
2676f9f848faSopenharmony_ci		rle->flags = 0;
2677f9f848faSopenharmony_ci	}
2678f9f848faSopenharmony_ci
2679f9f848faSopenharmony_ci	if (rle->res)
2680f9f848faSopenharmony_ci		panic("resource_list_add: resource entry is busy");
2681f9f848faSopenharmony_ci
2682f9f848faSopenharmony_ci	rle->res = bsd_malloc(sizeof(struct resource), M_BUS, M_NOWAIT);
2683f9f848faSopenharmony_ci	if (rle->res == NULL) {
2684f9f848faSopenharmony_ci		panic("resource_list_add: resource is busy");
2685f9f848faSopenharmony_ci	}
2686f9f848faSopenharmony_ci	rle->res->start = start;
2687f9f848faSopenharmony_ci	rle->res->end = end;
2688f9f848faSopenharmony_ci	rle->res->count = count;
2689f9f848faSopenharmony_ci	return (rle);
2690f9f848faSopenharmony_ci}
2691f9f848faSopenharmony_ci
2692f9f848faSopenharmony_ci/**
2693f9f848faSopenharmony_ci * @brief Find a resource entry by type and rid.
2694f9f848faSopenharmony_ci *
2695f9f848faSopenharmony_ci * @param rl		the resource list to search
2696f9f848faSopenharmony_ci * @param type		the resource entry type (e.g. SYS_RES_MEMORY)
2697f9f848faSopenharmony_ci * @param rid		the resource identifier
2698f9f848faSopenharmony_ci *
2699f9f848faSopenharmony_ci * @returns the resource entry pointer or NULL if there is no such
2700f9f848faSopenharmony_ci * entry.
2701f9f848faSopenharmony_ci */
2702f9f848faSopenharmony_cistruct resource_list_entry *
2703f9f848faSopenharmony_ciresource_list_find(struct resource_list *rl, int type, int rid)
2704f9f848faSopenharmony_ci{
2705f9f848faSopenharmony_ci	struct resource_list_entry *rle = NULL;
2706f9f848faSopenharmony_ci
2707f9f848faSopenharmony_ci	STAILQ_FOREACH(rle, rl, link) {
2708f9f848faSopenharmony_ci		if (rle->type == type && rle->rid == rid)
2709f9f848faSopenharmony_ci			return (rle);
2710f9f848faSopenharmony_ci	}
2711f9f848faSopenharmony_ci	return (NULL);
2712f9f848faSopenharmony_ci}
2713f9f848faSopenharmony_ci
2714f9f848faSopenharmony_ci/**
2715f9f848faSopenharmony_ci * @brief Wrapper function for BUS_ALLOC_RESOURCE().
2716f9f848faSopenharmony_ci *
2717f9f848faSopenharmony_ci * This function simply calls the BUS_ALLOC_RESOURCE() method of the
2718f9f848faSopenharmony_ci * parent of @p dev.
2719f9f848faSopenharmony_ci */
2720f9f848faSopenharmony_cistruct resource *
2721f9f848faSopenharmony_cibus_alloc_resource(device_t dev, int type, int *rid, rman_res_t start,
2722f9f848faSopenharmony_ci    rman_res_t end, rman_res_t count, u_int flags)
2723f9f848faSopenharmony_ci{
2724f9f848faSopenharmony_ci	struct resource *res = NULL;
2725f9f848faSopenharmony_ci
2726f9f848faSopenharmony_ci	if (dev->parent == NULL)
2727f9f848faSopenharmony_ci		return (NULL);
2728f9f848faSopenharmony_ci	res = BUS_ALLOC_RESOURCE(dev->parent, dev, type, rid, start, end,
2729f9f848faSopenharmony_ci	    count, flags);
2730f9f848faSopenharmony_ci	return (res);
2731f9f848faSopenharmony_ci}
2732f9f848faSopenharmony_ci
2733f9f848faSopenharmony_ci// root driver
2734f9f848faSopenharmony_cistatic int
2735f9f848faSopenharmony_ciroot_print_child(device_t dev, device_t child)
2736f9f848faSopenharmony_ci{
2737f9f848faSopenharmony_ci        int     retval = 0;
2738f9f848faSopenharmony_ci
2739f9f848faSopenharmony_ci        retval += bus_print_child_header(dev, child);
2740f9f848faSopenharmony_ci        retval += printf("\n");
2741f9f848faSopenharmony_ci
2742f9f848faSopenharmony_ci        return (retval);
2743f9f848faSopenharmony_ci}
2744f9f848faSopenharmony_ci
2745f9f848faSopenharmony_cistatic kobj_method_t root_methods[] = {
2746f9f848faSopenharmony_ci	/* Device interface */
2747f9f848faSopenharmony_ci	KOBJMETHOD(device_shutdown,     bus_generic_shutdown),
2748f9f848faSopenharmony_ci	KOBJMETHOD(device_suspend,      bus_generic_suspend),
2749f9f848faSopenharmony_ci	KOBJMETHOD(device_resume,       bus_generic_resume),
2750f9f848faSopenharmony_ci
2751f9f848faSopenharmony_ci				        /* Bus interface */
2752f9f848faSopenharmony_ci	KOBJMETHOD(bus_print_child,     root_print_child),
2753f9f848faSopenharmony_ci
2754f9f848faSopenharmony_ci	KOBJMETHOD_END
2755f9f848faSopenharmony_ci};
2756f9f848faSopenharmony_ci
2757f9f848faSopenharmony_cistatic driver_t root_driver = {
2758f9f848faSopenharmony_ci	"root",
2759f9f848faSopenharmony_ci	root_methods,
2760f9f848faSopenharmony_ci	1,                      /* no softc */
2761f9f848faSopenharmony_ci};
2762f9f848faSopenharmony_ci
2763f9f848faSopenharmony_cidevice_t        root_bus;
2764f9f848faSopenharmony_cidevclass_t      root_devclass;
2765f9f848faSopenharmony_ci
2766f9f848faSopenharmony_cistatic int
2767f9f848faSopenharmony_ciroot_bus_module_handler(module_t mod, int what, void* arg)
2768f9f848faSopenharmony_ci{
2769f9f848faSopenharmony_ci        PDEBUG(("+"));
2770f9f848faSopenharmony_ci        switch (what) {
2771f9f848faSopenharmony_ci        case MOD_LOAD:
2772f9f848faSopenharmony_ci                TAILQ_INIT(&bus_data_devices);
2773f9f848faSopenharmony_ci                kobj_class_compile((kobj_class_t) &root_driver);
2774f9f848faSopenharmony_ci                root_bus = make_device(NULL, "root", 0);
2775f9f848faSopenharmony_ci                root_bus->desc = "System root bus";
2776f9f848faSopenharmony_ci                kobj_init((kobj_t) root_bus, (kobj_class_t) &root_driver);
2777f9f848faSopenharmony_ci                root_bus->driver = &root_driver;
2778f9f848faSopenharmony_ci                root_bus->state = DS_ATTACHED;
2779f9f848faSopenharmony_ci                root_devclass = devclass_find_internal("root", NULL, FALSE);
2780f9f848faSopenharmony_ci                //devinit();
2781f9f848faSopenharmony_ci                return (0);
2782f9f848faSopenharmony_ci
2783f9f848faSopenharmony_ci        case MOD_SHUTDOWN:
2784f9f848faSopenharmony_ci                device_shutdown(root_bus);
2785f9f848faSopenharmony_ci                return (0);
2786f9f848faSopenharmony_ci        default:
2787f9f848faSopenharmony_ci                return (EOPNOTSUPP);
2788f9f848faSopenharmony_ci        }
2789f9f848faSopenharmony_ci        PDEBUG(("-"));
2790f9f848faSopenharmony_ci
2791f9f848faSopenharmony_ci        return (0);
2792f9f848faSopenharmony_ci}
2793f9f848faSopenharmony_ci
2794f9f848faSopenharmony_ci/**
2795f9f848faSopenharmony_ci * @brief Automatically configure devices
2796f9f848faSopenharmony_ci *
2797f9f848faSopenharmony_ci * This function begins the autoconfiguration process by calling
2798f9f848faSopenharmony_ci * device_probe_and_attach() for each child of the @c root0 device.
2799f9f848faSopenharmony_ci */
2800f9f848faSopenharmony_civoid
2801f9f848faSopenharmony_ciroot_bus_configure(void)
2802f9f848faSopenharmony_ci{
2803f9f848faSopenharmony_ci	PDEBUG(("+"));
2804f9f848faSopenharmony_ci        root_bus_module_handler(NULL, MOD_LOAD, NULL);
2805f9f848faSopenharmony_ci
2806f9f848faSopenharmony_ci	/* Eventually this will be split up, but this is sufficient for now. */
2807f9f848faSopenharmony_ci	bus_set_pass(BUS_PASS_DEFAULT);
2808f9f848faSopenharmony_ci	PDEBUG(("-"));
2809f9f848faSopenharmony_ci}
2810f9f848faSopenharmony_ci
2811f9f848faSopenharmony_ci/**
2812f9f848faSopenharmony_ci * @brief Module handler for registering device drivers
2813f9f848faSopenharmony_ci *
2814f9f848faSopenharmony_ci * This module handler is used to automatically register device
2815f9f848faSopenharmony_ci * drivers when modules are loaded. If @p what is MOD_LOAD, it calls
2816f9f848faSopenharmony_ci * devclass_add_driver() for the driver described by the
2817f9f848faSopenharmony_ci * driver_module_data structure pointed to by @p arg
2818f9f848faSopenharmony_ci */
2819f9f848faSopenharmony_ciint
2820f9f848faSopenharmony_cidriver_module_handler(module_t mod, int what, void *arg)
2821f9f848faSopenharmony_ci{
2822f9f848faSopenharmony_ci        struct driver_module_data *dmd = NULL;
2823f9f848faSopenharmony_ci        devclass_t bus_devclass;
2824f9f848faSopenharmony_ci        kobj_class_t driver;
2825f9f848faSopenharmony_ci        int error, pass;
2826f9f848faSopenharmony_ci
2827f9f848faSopenharmony_ci        PDEBUG(("+"));
2828f9f848faSopenharmony_ci
2829f9f848faSopenharmony_ci        dmd = (struct driver_module_data *)arg;
2830f9f848faSopenharmony_ci        bus_devclass = devclass_find_internal(dmd->dmd_busname, NULL, TRUE);
2831f9f848faSopenharmony_ci        if (bus_devclass == NULL) {
2832f9f848faSopenharmony_ci                PDEBUG(("-"));
2833f9f848faSopenharmony_ci                return EINVAL;
2834f9f848faSopenharmony_ci        }
2835f9f848faSopenharmony_ci
2836f9f848faSopenharmony_ci        error = 0;
2837f9f848faSopenharmony_ci
2838f9f848faSopenharmony_ci        switch (what) {
2839f9f848faSopenharmony_ci        case MOD_LOAD:
2840f9f848faSopenharmony_ci                if (dmd->dmd_chainevh)
2841f9f848faSopenharmony_ci                        error = dmd->dmd_chainevh(mod,what,dmd->dmd_chainarg);
2842f9f848faSopenharmony_ci
2843f9f848faSopenharmony_ci                pass = dmd->dmd_pass;
2844f9f848faSopenharmony_ci                driver = dmd->dmd_driver;
2845f9f848faSopenharmony_ci                PDEBUG(("Loading module: driver %s on bus %s (pass %d)",
2846f9f848faSopenharmony_ci                    DRIVERNAME(driver), dmd->dmd_busname, pass));
2847f9f848faSopenharmony_ci                error = devclass_add_driver(bus_devclass, driver, pass,
2848f9f848faSopenharmony_ci                    dmd->dmd_devclass);
2849f9f848faSopenharmony_ci                break;
2850f9f848faSopenharmony_ci
2851f9f848faSopenharmony_ci        case MOD_UNLOAD:
2852f9f848faSopenharmony_ci                PDEBUG(("Unloading module: driver %s from bus %s",
2853f9f848faSopenharmony_ci                    DRIVERNAME(dmd->dmd_driver),
2854f9f848faSopenharmony_ci                    dmd->dmd_busname));
2855f9f848faSopenharmony_ci                error = devclass_delete_driver(bus_devclass,
2856f9f848faSopenharmony_ci                    dmd->dmd_driver);
2857f9f848faSopenharmony_ci
2858f9f848faSopenharmony_ci                if (!error && dmd->dmd_chainevh)
2859f9f848faSopenharmony_ci                        error = dmd->dmd_chainevh(mod,what,dmd->dmd_chainarg);
2860f9f848faSopenharmony_ci                break;
2861f9f848faSopenharmony_ci        case MOD_QUIESCE:
2862f9f848faSopenharmony_ci                PDEBUG(("Quiesce module: driver %s from bus %s",
2863f9f848faSopenharmony_ci                    DRIVERNAME(dmd->dmd_driver),
2864f9f848faSopenharmony_ci                    dmd->dmd_busname));
2865f9f848faSopenharmony_ci                error = devclass_quiesce_driver(bus_devclass,
2866f9f848faSopenharmony_ci                    dmd->dmd_driver);
2867f9f848faSopenharmony_ci
2868f9f848faSopenharmony_ci                if (!error && dmd->dmd_chainevh)
2869f9f848faSopenharmony_ci                        error = dmd->dmd_chainevh(mod,what,dmd->dmd_chainarg);
2870f9f848faSopenharmony_ci                break;
2871f9f848faSopenharmony_ci        default:
2872f9f848faSopenharmony_ci                error = EOPNOTSUPP;
2873f9f848faSopenharmony_ci                break;
2874f9f848faSopenharmony_ci        }
2875f9f848faSopenharmony_ci        PDEBUG(("-"));
2876f9f848faSopenharmony_ci
2877f9f848faSopenharmony_ci        return (error);
2878f9f848faSopenharmony_ci}
2879f9f848faSopenharmony_ci
2880f9f848faSopenharmony_ci#ifdef BUS_DEBUG
2881f9f848faSopenharmony_ci
2882f9f848faSopenharmony_ci/* the _short versions avoid iteration by not calling anything that prints
2883f9f848faSopenharmony_ci * more than oneliners. I love oneliners.
2884f9f848faSopenharmony_ci */
2885f9f848faSopenharmony_ci
2886f9f848faSopenharmony_cistatic void
2887f9f848faSopenharmony_ciprint_device_short(device_t dev, int indent)
2888f9f848faSopenharmony_ci{
2889f9f848faSopenharmony_ci        if (!dev)
2890f9f848faSopenharmony_ci                return;
2891f9f848faSopenharmony_ci
2892f9f848faSopenharmony_ci        indentprintf(("device %d: <%s> %sparent,%schildren,%s%s%s%s%s,%sivars,%ssoftc,busy=%d\n",
2893f9f848faSopenharmony_ci            dev->unit, dev->desc,
2894f9f848faSopenharmony_ci            (dev->parent? "":"no "),
2895f9f848faSopenharmony_ci            (TAILQ_EMPTY(&dev->children)? "no ":""),
2896f9f848faSopenharmony_ci            (dev->flags&DF_ENABLED? "enabled,":"disabled,"),
2897f9f848faSopenharmony_ci            (dev->flags&DF_FIXEDCLASS? "fixed,":""),
2898f9f848faSopenharmony_ci            (dev->flags&DF_WILDCARD? "wildcard,":""),
2899f9f848faSopenharmony_ci            (dev->flags&DF_DESCMALLOCED? "descmalloced,":""),
2900f9f848faSopenharmony_ci            (dev->flags&DF_REBID? "rebiddable,":""),
2901f9f848faSopenharmony_ci            (dev->ivars? "":"no "),
2902f9f848faSopenharmony_ci            (dev->softc? "":"no "),
2903f9f848faSopenharmony_ci            dev->busy));
2904f9f848faSopenharmony_ci}
2905f9f848faSopenharmony_ci
2906f9f848faSopenharmony_cistatic void
2907f9f848faSopenharmony_ciprint_device(device_t dev, int indent)
2908f9f848faSopenharmony_ci{
2909f9f848faSopenharmony_ci        if (!dev)
2910f9f848faSopenharmony_ci                return;
2911f9f848faSopenharmony_ci
2912f9f848faSopenharmony_ci        print_device_short(dev, indent);
2913f9f848faSopenharmony_ci
2914f9f848faSopenharmony_ci        indentprintf(("Parent:\n"));
2915f9f848faSopenharmony_ci        print_device_short(dev->parent, indent+1);
2916f9f848faSopenharmony_ci        indentprintf(("Driver:\n"));
2917f9f848faSopenharmony_ci        print_driver_short(dev->driver, indent+1);
2918f9f848faSopenharmony_ci        indentprintf(("Devclass:\n"));
2919f9f848faSopenharmony_ci        print_devclass_short(dev->devclass, indent+1);
2920f9f848faSopenharmony_ci}
2921f9f848faSopenharmony_ci
2922f9f848faSopenharmony_civoid
2923f9f848faSopenharmony_ciprint_device_tree_short(device_t dev, int indent)
2924f9f848faSopenharmony_ci/* print the device and all its children (indented) */
2925f9f848faSopenharmony_ci{
2926f9f848faSopenharmony_ci        device_t child;
2927f9f848faSopenharmony_ci
2928f9f848faSopenharmony_ci        if (!dev)
2929f9f848faSopenharmony_ci                return;
2930f9f848faSopenharmony_ci
2931f9f848faSopenharmony_ci        print_device_short(dev, indent);
2932f9f848faSopenharmony_ci
2933f9f848faSopenharmony_ci        TAILQ_FOREACH(child, &dev->children, link) {
2934f9f848faSopenharmony_ci                print_device_tree_short(child, indent+1);
2935f9f848faSopenharmony_ci        }
2936f9f848faSopenharmony_ci}
2937f9f848faSopenharmony_ci
2938f9f848faSopenharmony_civoid
2939f9f848faSopenharmony_ciprint_device_tree(device_t dev, int indent)
2940f9f848faSopenharmony_ci/* print the device and all its children (indented) */
2941f9f848faSopenharmony_ci{
2942f9f848faSopenharmony_ci        device_t child;
2943f9f848faSopenharmony_ci
2944f9f848faSopenharmony_ci        if (!dev)
2945f9f848faSopenharmony_ci                return;
2946f9f848faSopenharmony_ci
2947f9f848faSopenharmony_ci        print_device(dev, indent);
2948f9f848faSopenharmony_ci
2949f9f848faSopenharmony_ci        TAILQ_FOREACH(child, &dev->children, link) {
2950f9f848faSopenharmony_ci                print_device_tree(child, indent+1);
2951f9f848faSopenharmony_ci        }
2952f9f848faSopenharmony_ci}
2953f9f848faSopenharmony_ci
2954f9f848faSopenharmony_cistatic void
2955f9f848faSopenharmony_ciprint_driver_short(driver_t *driver, int indent)
2956f9f848faSopenharmony_ci{
2957f9f848faSopenharmony_ci        if (!driver)
2958f9f848faSopenharmony_ci                return;
2959f9f848faSopenharmony_ci
2960f9f848faSopenharmony_ci        indentprintf(("driver %s: softc size = %zd\n",
2961f9f848faSopenharmony_ci            driver->name, driver->size));
2962f9f848faSopenharmony_ci}
2963f9f848faSopenharmony_ci
2964f9f848faSopenharmony_cistatic void
2965f9f848faSopenharmony_ciprint_driver(driver_t *driver, int indent)
2966f9f848faSopenharmony_ci{
2967f9f848faSopenharmony_ci        if (!driver)
2968f9f848faSopenharmony_ci                return;
2969f9f848faSopenharmony_ci
2970f9f848faSopenharmony_ci        print_driver_short(driver, indent);
2971f9f848faSopenharmony_ci}
2972f9f848faSopenharmony_ci
2973f9f848faSopenharmony_cistatic void
2974f9f848faSopenharmony_ciprint_driver_list(driver_list_t drivers, int indent)
2975f9f848faSopenharmony_ci{
2976f9f848faSopenharmony_ci        driverlink_t driver = NULL;
2977f9f848faSopenharmony_ci
2978f9f848faSopenharmony_ci        TAILQ_FOREACH(driver, &drivers, link) {
2979f9f848faSopenharmony_ci                print_driver(driver->driver, indent);
2980f9f848faSopenharmony_ci        }
2981f9f848faSopenharmony_ci}
2982f9f848faSopenharmony_ci
2983f9f848faSopenharmony_cistatic void
2984f9f848faSopenharmony_ciprint_devclass_short(devclass_t dc, int indent)
2985f9f848faSopenharmony_ci{
2986f9f848faSopenharmony_ci        if ( !dc )
2987f9f848faSopenharmony_ci                return;
2988f9f848faSopenharmony_ci
2989f9f848faSopenharmony_ci        indentprintf(("devclass %s: max units = %d\n", dc->name, dc->maxunit));
2990f9f848faSopenharmony_ci}
2991f9f848faSopenharmony_ci
2992f9f848faSopenharmony_cistatic void
2993f9f848faSopenharmony_ciprint_devclass(devclass_t dc, int indent)
2994f9f848faSopenharmony_ci{
2995f9f848faSopenharmony_ci        int i;
2996f9f848faSopenharmony_ci
2997f9f848faSopenharmony_ci        if ( !dc )
2998f9f848faSopenharmony_ci                return;
2999f9f848faSopenharmony_ci
3000f9f848faSopenharmony_ci        print_devclass_short(dc, indent);
3001f9f848faSopenharmony_ci        indentprintf(("Drivers:\n"));
3002f9f848faSopenharmony_ci        print_driver_list(dc->drivers, indent+1);
3003f9f848faSopenharmony_ci
3004f9f848faSopenharmony_ci        indentprintf(("Devices:\n"));
3005f9f848faSopenharmony_ci        for (i = 0; i < dc->maxunit; i++)
3006f9f848faSopenharmony_ci                if (dc->devices[i])
3007f9f848faSopenharmony_ci                        print_device(dc->devices[i], indent+1);
3008f9f848faSopenharmony_ci}
3009f9f848faSopenharmony_ci
3010f9f848faSopenharmony_civoid
3011f9f848faSopenharmony_ciprint_devclass_list_short(void)
3012f9f848faSopenharmony_ci{
3013f9f848faSopenharmony_ci        devclass_t dc;
3014f9f848faSopenharmony_ci
3015f9f848faSopenharmony_ci        printf("Short listing of devclasses, drivers & devices:\n");
3016f9f848faSopenharmony_ci        TAILQ_FOREACH(dc, &devclasses, link) {
3017f9f848faSopenharmony_ci                print_devclass_short(dc, 0);
3018f9f848faSopenharmony_ci        }
3019f9f848faSopenharmony_ci}
3020f9f848faSopenharmony_ci
3021f9f848faSopenharmony_civoid
3022f9f848faSopenharmony_ciprint_devclass_list(void)
3023f9f848faSopenharmony_ci{
3024f9f848faSopenharmony_ci        devclass_t dc;
3025f9f848faSopenharmony_ci
3026f9f848faSopenharmony_ci        printf("Full listing of devclasses, drivers & devices:\n");
3027f9f848faSopenharmony_ci        TAILQ_FOREACH(dc, &devclasses, link) {
3028f9f848faSopenharmony_ci                print_devclass(dc, 0);
3029f9f848faSopenharmony_ci        }
3030f9f848faSopenharmony_ci}
3031f9f848faSopenharmony_ci
3032f9f848faSopenharmony_ci#endif
3033f9f848faSopenharmony_ci
3034f9f848faSopenharmony_ci/* port for interrupt setup and teardown */
3035f9f848faSopenharmony_ciint
3036f9f848faSopenharmony_cibus_setup_intr(int irq, int flags, driver_intr_t *intr, void *arg)
3037f9f848faSopenharmony_ci{
3038f9f848faSopenharmony_ci        int ret;
3039f9f848faSopenharmony_ci        HwiIrqParam irqParam = {0};
3040f9f848faSopenharmony_ci
3041f9f848faSopenharmony_ci        if (OS_INT_ACTIVE) {
3042f9f848faSopenharmony_ci                return OS_ERRNO_HWI_INTERR;
3043f9f848faSopenharmony_ci        }
3044f9f848faSopenharmony_ci
3045f9f848faSopenharmony_ci        irqParam.swIrq  = irq;
3046f9f848faSopenharmony_ci        irqParam.pDevId = arg;
3047f9f848faSopenharmony_ci
3048f9f848faSopenharmony_ci        ret = LOS_HwiCreate(irq, 0, (HWI_MODE_T)flags, (HWI_PROC_FUNC)intr, &irqParam);
3049f9f848faSopenharmony_ci        if (ret == LOS_OK) {
3050f9f848faSopenharmony_ci                HalIrqUnmask(irq);
3051f9f848faSopenharmony_ci        }
3052f9f848faSopenharmony_ci        return ret;
3053f9f848faSopenharmony_ci}
3054f9f848faSopenharmony_ciint
3055f9f848faSopenharmony_cibus_teardown_intr(int irq, void *arg)
3056f9f848faSopenharmony_ci{
3057f9f848faSopenharmony_ci    HwiIrqParam irqParam = {0};
3058f9f848faSopenharmony_ci
3059f9f848faSopenharmony_ci    if (OS_INT_ACTIVE) {
3060f9f848faSopenharmony_ci        return -1;
3061f9f848faSopenharmony_ci    }
3062f9f848faSopenharmony_ci
3063f9f848faSopenharmony_ci    irqParam.swIrq  = irq;
3064f9f848faSopenharmony_ci    irqParam.pDevId = arg;
3065f9f848faSopenharmony_ci
3066f9f848faSopenharmony_ci    return LOS_HwiDelete(irq, &irqParam);
3067f9f848faSopenharmony_ci}
3068