2 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
25 #include "hal-backend-common-udev.h"
26 #include "hal-backend-common.h"
28 #define EVENT_KERNEL "kernel"
29 #define EVENT_UDEV "udev"
31 #define UDEV_MONITOR_BUFFER_SIZE (128*1024)
34 struct udev_monitor *mon;
44 static struct uevent_info kevent; /* kernel */
45 static struct uevent_info uevent; /* udev */
47 static gboolean uevent_control_cb(GIOChannel *channel,
48 GIOCondition cond, void *data)
50 struct uevent_info *info = data;
51 struct udev_device *dev;
52 struct uevent_handler *l;
54 const char *subsystem;
58 _E("data is invalid");
62 dev = udev_monitor_receive_device(info->mon);
66 subsystem = udev_device_get_subsystem(dev);
70 len = strlen(subsystem);
72 for (elem = info->event_list ; elem ; elem = g_list_next(elem)) {
76 if (!strncmp(l->subsystem, subsystem, len) &&
82 udev_device_unref(dev);
86 static int uevent_control_stop(struct uevent_info *info)
88 struct udev_device *dev;
97 g_source_remove(info->eventid);
101 g_io_channel_unref(info->ch);
105 dev = udev_monitor_receive_device(info->mon);
107 udev_device_unref(dev);
108 udev_monitor_unref(info->mon);
112 info->udev = udev_unref(info->udev);
117 static int uevent_control_start(const char *type,
118 struct uevent_info *info)
127 info->udev = udev_new();
129 _E("error create udev");
138 info->mon = udev_monitor_new_from_netlink(info->udev, type);
139 if (info->mon == NULL) {
140 _E("error udev_monitor create");
144 _I("Set udev monitor buffer size %d", UDEV_MONITOR_BUFFER_SIZE);
145 ret = udev_monitor_set_receive_buffer_size(info->mon,
146 UDEV_MONITOR_BUFFER_SIZE);
148 _E("fail to set receive buffer size");
152 fd = udev_monitor_get_fd(info->mon);
154 _E("error udev_monitor_get_fd");
158 info->ch = g_io_channel_unix_new(fd);
159 info->eventid = g_io_add_watch(info->ch,
160 G_IO_IN, uevent_control_cb, info);
161 if (info->eventid == 0) {
162 _E("Failed to add channel watch");
166 if (udev_monitor_enable_receiving(info->mon) < 0) {
167 _E("error unable to subscribe to udev events");
173 uevent_control_stop(info);
177 EXPORT int uevent_control_kernel_start(void)
179 return uevent_control_start(EVENT_KERNEL, &kevent);
182 EXPORT void uevent_control_kernel_stop(void)
184 uevent_control_stop(&kevent);
187 EXPORT int uevent_control_udev_start(void)
189 return uevent_control_start(EVENT_UDEV, &uevent);
192 EXPORT void uevent_control_udev_stop(void)
194 uevent_control_stop(&uevent);
197 static int register_uevent_control(struct uevent_info *info,
198 struct uevent_handler *uh)
200 struct uevent_handler *l;
205 if (!info || !uh || !uh->subsystem)
208 /* if udev is not initialized, it just will be added list */
209 if (!info->udev || !info->mon)
212 len = strlen(uh->subsystem);
213 /* check if the same subsystem is already added */
214 for (elem = info->event_list; elem ; elem = g_list_next(elem)) {
216 if (!strncmp(l->subsystem, uh->subsystem, len))
220 /* the first request to add subsystem */
221 r = udev_monitor_filter_add_match_subsystem_devtype(info->mon,
222 uh->subsystem, NULL);
224 _E("fail to add %s subsystem : %d", uh->subsystem, r);
228 r = udev_monitor_filter_update(info->mon);
230 _E("fail to update udev monitor filter : %d", r);
233 info->event_list = g_list_append(info->event_list, uh);
237 static int unregister_uevent_control(struct uevent_info *info,
238 const struct uevent_handler *uh)
240 struct uevent_handler *l;
244 if (!info || !uh || !uh->subsystem)
247 len = strlen(uh->subsystem);
248 for (n = info->event_list, next = g_list_next(n) ;
249 n ; n = next, next = g_list_next(n)) {
251 if (!strncmp(l->subsystem, uh->subsystem, len) &&
252 l->uevent_func == uh->uevent_func) {
253 info->event_list = g_list_delete_link(info->event_list, n);
261 EXPORT int register_kernel_event_control(struct uevent_handler *uh)
263 return register_uevent_control(&kevent, uh);
266 EXPORT void unregister_kernel_event_control(struct uevent_handler *uh)
268 unregister_uevent_control(&kevent, uh);
271 EXPORT int register_udev_event_control(struct uevent_handler *uh)
273 return register_uevent_control(&uevent, uh);
276 EXPORT void unregister_udev_event_control(struct uevent_handler *uh)
278 unregister_uevent_control(&uevent, uh);