blob: 5636a708bc35a04cec43091e92c987bf89ecbb32 [file] [log] [blame]
Kumar Galad12d8af2016-10-05 12:01:54 -05001/*
2 * Copyright (c) 2015-2016 Intel Corporation.
3 *
David B. Kinderac74d8b2017-01-18 17:01:01 -08004 * SPDX-License-Identifier: Apache-2.0
Kumar Galad12d8af2016-10-05 12:01:54 -05005 */
6
Kumar Galad12d8af2016-10-05 12:01:54 -05007#include <string.h>
8#include <device.h>
Anas Nashife1e05a22019-06-25 12:25:32 -04009#include <sys/atomic.h>
Andrew Boie9d148742018-11-12 10:25:12 -080010#include <syscall_handler.h>
Kumar Galad12d8af2016-10-05 12:01:54 -050011
12extern struct device __device_init_start[];
Andrew Boie0b474ee2016-11-08 11:06:55 -080013extern struct device __device_PRE_KERNEL_1_start[];
14extern struct device __device_PRE_KERNEL_2_start[];
15extern struct device __device_POST_KERNEL_start[];
16extern struct device __device_APPLICATION_start[];
Kumar Galad12d8af2016-10-05 12:01:54 -050017extern struct device __device_init_end[];
18
Kumar Galad12d8af2016-10-05 12:01:54 -050019
20#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
Kumar Galacc334c72017-04-21 10:55:34 -050021extern u32_t __device_busy_start[];
22extern u32_t __device_busy_end[];
Kumar Galad12d8af2016-10-05 12:01:54 -050023#define DEVICE_BUSY_SIZE (__device_busy_end - __device_busy_start)
24#endif
25
26/**
27 * @brief Execute all the device initialization functions at a given level
28 *
29 * @details Invokes the initialization routine for each device object
30 * created by the DEVICE_INIT() macro using the specified level.
31 * The linker script places the device objects in memory in the order
32 * they need to be invoked, with symbols indicating where one level leaves
33 * off and the next one begins.
34 *
35 * @param level init level to run.
36 */
Patrik Flykt4344e272019-03-08 14:19:05 -070037void z_sys_device_do_config_level(s32_t level)
Kumar Galad12d8af2016-10-05 12:01:54 -050038{
39 struct device *info;
Flavio Ceolinac146852018-11-01 17:42:07 -070040 static struct device *config_levels[] = {
41 __device_PRE_KERNEL_1_start,
42 __device_PRE_KERNEL_2_start,
43 __device_POST_KERNEL_start,
44 __device_APPLICATION_start,
45 /* End marker */
46 __device_init_end,
47 };
Kumar Galad12d8af2016-10-05 12:01:54 -050048
Amir Kaplan61b6f5a2017-03-22 14:49:34 +020049 for (info = config_levels[level]; info < config_levels[level+1];
50 info++) {
Andrew Boiea68120d2018-12-07 13:12:21 -080051 int retval;
Krzysztof Chruscinskia8b5a2e2020-01-21 08:26:19 +010052 const struct device_config *device_conf = info->config;
Kumar Galad12d8af2016-10-05 12:01:54 -050053
Andrew Boiea68120d2018-12-07 13:12:21 -080054 retval = device_conf->init(info);
55 if (retval != 0) {
56 /* Initialization failed. Clear the API struct so that
57 * device_get_binding() will not succeed for it.
58 */
59 info->driver_api = NULL;
60 } else {
Patrik Flykt4344e272019-03-08 14:19:05 -070061 z_object_init(info);
Andrew Boiea68120d2018-12-07 13:12:21 -080062 }
Kumar Galad12d8af2016-10-05 12:01:54 -050063 }
64}
65
Patrik Flykt4344e272019-03-08 14:19:05 -070066struct device *z_impl_device_get_binding(const char *name)
Kumar Galad12d8af2016-10-05 12:01:54 -050067{
68 struct device *info;
69
Leandro Pereirab55eb032018-02-14 14:47:11 -080070 /* Split the search into two loops: in the common scenario, where
71 * device names are stored in ROM (and are referenced by the user
72 * with CONFIG_* macros), only cheap pointer comparisons will be
73 * performed. Reserve string comparisons for a fallback.
74 */
75 for (info = __device_init_start; info != __device_init_end; info++) {
Adithya Baglody8feda922018-10-25 12:04:25 +053076 if ((info->driver_api != NULL) &&
77 (info->config->name == name)) {
Leandro Pereirab55eb032018-02-14 14:47:11 -080078 return info;
79 }
80 }
81
Kumar Galad12d8af2016-10-05 12:01:54 -050082 for (info = __device_init_start; info != __device_init_end; info++) {
Adithya Baglody8feda922018-10-25 12:04:25 +053083 if (info->driver_api == NULL) {
Leandro Pereirad24daa42017-10-19 14:17:37 -070084 continue;
85 }
86
Adithya Baglody8feda922018-10-25 12:04:25 +053087 if (strcmp(name, info->config->name) == 0) {
Kumar Galad12d8af2016-10-05 12:01:54 -050088 return info;
89 }
90 }
91
92 return NULL;
93}
94
Andrew Boie9d148742018-11-12 10:25:12 -080095#ifdef CONFIG_USERSPACE
Andy Ross65649742019-08-06 13:34:31 -070096static inline struct device *z_vrfy_device_get_binding(const char *name)
Andrew Boie9d148742018-11-12 10:25:12 -080097{
98 char name_copy[Z_DEVICE_MAX_NAME_LEN];
99
100 if (z_user_string_copy(name_copy, (char *)name, sizeof(name_copy))
101 != 0) {
102 return 0;
103 }
104
Andy Ross65649742019-08-06 13:34:31 -0700105 return z_impl_device_get_binding(name_copy);
Andrew Boie9d148742018-11-12 10:25:12 -0800106}
Andy Ross65649742019-08-06 13:34:31 -0700107#include <syscalls/device_get_binding_mrsh.c>
Andrew Boie9d148742018-11-12 10:25:12 -0800108#endif /* CONFIG_USERSPACE */
109
Kumar Galad12d8af2016-10-05 12:01:54 -0500110#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
Ramesh Thomas6249c562016-10-07 17:07:04 -0700111int device_pm_control_nop(struct device *unused_device,
Ramakrishna Pallalae1639b52019-02-14 09:35:42 +0530112 u32_t unused_ctrl_command,
113 void *unused_context,
114 device_pm_cb cb,
115 void *unused_arg)
Kumar Galad12d8af2016-10-05 12:01:54 -0500116{
117 return 0;
118}
Ramesh Thomas6249c562016-10-07 17:07:04 -0700119
Kumar Galad12d8af2016-10-05 12:01:54 -0500120void device_list_get(struct device **device_list, int *device_count)
121{
122
123 *device_list = __device_init_start;
124 *device_count = __device_init_end - __device_init_start;
125}
126
127
128int device_any_busy_check(void)
129{
130 int i = 0;
131
132 for (i = 0; i < DEVICE_BUSY_SIZE; i++) {
Patrik Flykt24d71432019-03-26 19:57:45 -0600133 if (__device_busy_start[i] != 0U) {
Kumar Galad12d8af2016-10-05 12:01:54 -0500134 return -EBUSY;
135 }
136 }
137 return 0;
138}
139
140int device_busy_check(struct device *chk_dev)
141{
142 if (atomic_test_bit((const atomic_t *)__device_busy_start,
143 (chk_dev - __device_init_start))) {
144 return -EBUSY;
145 }
146 return 0;
147}
148
149#endif
150
151void device_busy_set(struct device *busy_dev)
152{
153#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
154 atomic_set_bit((atomic_t *) __device_busy_start,
155 (busy_dev - __device_init_start));
Flavio Santesb80db0a2016-12-11 00:19:26 -0600156#else
157 ARG_UNUSED(busy_dev);
Kumar Galad12d8af2016-10-05 12:01:54 -0500158#endif
159}
160
161void device_busy_clear(struct device *busy_dev)
162{
163#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
164 atomic_clear_bit((atomic_t *) __device_busy_start,
165 (busy_dev - __device_init_start));
Flavio Santesb80db0a2016-12-11 00:19:26 -0600166#else
167 ARG_UNUSED(busy_dev);
Kumar Galad12d8af2016-10-05 12:01:54 -0500168#endif
169}