1/****************************************************************************
2**
3** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtSystems module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL21$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 or version 3 as published by the Free
20** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22** following information to ensure the GNU Lesser General Public License
23** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25**
26** As a special exception, The Qt Company gives you certain additional
27** rights. These rights are described in The Qt Company LGPL Exception
28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29**
30** $QT_END_LICENSE$
31**
32****************************************************************************/
33
34#include "qudevwrapper_p.h"
35
36#include <QMetaMethod>
37#include <QSocketNotifier>
38
39#include <poll.h>
40#include <sys/select.h>
41#if !defined(QT_NO_UDEV)
42
43QT_BEGIN_NAMESPACE
44
45QUDevWrapper::QUDevWrapper(QObject *parent)
46 : QObject(parent)
47 , udev(0)
48 , udevMonitor(0)
49 , udevFd(-1)
50 , notifier(0)
51 , watcherEnabled(false)
52 , watchPowerSupply(false)
53 , watchDrives(false)
54{
55}
56
57bool QUDevWrapper::addUDevWatcher(const QByteArray &subsystem)
58{
59 if (!udev)
60 udev = udev_new();
61
62 if (udev && !udevMonitor)
63 udevMonitor = udev_monitor_new_from_netlink(udev, name: "udev");
64
65 if (udevMonitor) {
66 if (udev_monitor_filter_add_match_subsystem_devtype(udev_monitor: udevMonitor, subsystem, NULL) >= 0) {
67 if (!watcherEnabled) {
68 if (udev_monitor_enable_receiving(udev_monitor: udevMonitor) >= 0) {
69 udevFd = udev_monitor_get_fd(udev_monitor: udevMonitor);
70 if (udevFd >= 0) {
71 notifier = new QSocketNotifier(udevFd, QSocketNotifier::Read, this);
72 if (connect(sender: notifier, SIGNAL(activated(int)), receiver: this, SLOT(onUDevChanges()))) {
73 watcherEnabled = true;
74 return true;
75 }
76 }
77 }
78 } else {
79 if (udev_monitor_filter_update(udev_monitor: udevMonitor) >= 0)
80 return true;
81 }
82 }
83 }
84 return false;
85}
86
87bool QUDevWrapper::removeAllUDevWatcher()
88{
89 if (!udev || !udevMonitor)
90 return true;
91
92 if (udev_monitor_filter_remove(udev_monitor: udevMonitor) >= 0) {
93 if (udev_monitor_filter_update(udev_monitor: udevMonitor) >= 0)
94 return true;
95 }
96 return false;
97}
98
99void QUDevWrapper::connectNotify(const QMetaMethod &signal)
100{
101 static const QMetaMethod driveChangedSignal = QMetaMethod::fromSignal(signal: &QUDevWrapper::driveChanged);
102 static const QMetaMethod batteryDataChangedSignal = QMetaMethod::fromSignal(signal: &QUDevWrapper::batteryDataChanged);
103 static const QMetaMethod chargerTypeChangedSignal = QMetaMethod::fromSignal(signal: &QUDevWrapper::chargerTypeChanged);
104
105 if (!watchDrives && signal == driveChangedSignal) {
106 if (addUDevWatcher(subsystem: "block"))
107 watchDrives = true;
108 } else if (!watchPowerSupply && (signal == batteryDataChangedSignal
109 || signal == chargerTypeChangedSignal)) {
110 if (addUDevWatcher(subsystem: "power_supply"))
111 watchPowerSupply = true;
112 }
113}
114void QUDevWrapper::disconnectNotify(const QMetaMethod &signal)
115{
116 static const QMetaMethod driveChangedSignal = QMetaMethod::fromSignal(signal: &QUDevWrapper::driveChanged);
117 static const QMetaMethod batteryDataChangedSignal = QMetaMethod::fromSignal(signal: &QUDevWrapper::batteryDataChanged);
118 static const QMetaMethod chargerTypeChangedSignal = QMetaMethod::fromSignal(signal: &QUDevWrapper::chargerTypeChanged);
119
120 if (watchDrives && signal == driveChangedSignal) {
121 if (removeAllUDevWatcher()) {
122 watchDrives = false;
123 if (watchPowerSupply) {
124 if (!addUDevWatcher(subsystem: "power_supply"))
125 watchPowerSupply = false;
126 }
127 }
128 } else if (watchPowerSupply && (signal == batteryDataChangedSignal
129 || signal == chargerTypeChangedSignal)) {
130 if (removeAllUDevWatcher()) {
131 watchPowerSupply = false;
132 if (watchDrives) {
133 if (!addUDevWatcher(subsystem: "block"))
134 watchDrives = false;
135 }
136 }
137 }
138
139 if (!watchDrives && !watchPowerSupply) {
140 disconnect(sender: notifier, SIGNAL(activated(int)), receiver: this, SLOT(onUDevChanges()));
141 udev_monitor_unref(udev_monitor: udevMonitor);
142 udevMonitor = 0;
143 udevFd = -1;
144 watcherEnabled = false;
145 udev_unref(udev);
146 }
147}
148
149void QUDevWrapper::onUDevChanges()
150{
151 int ret;
152 struct udev_device *device = 0;
153 QByteArray subsystem;
154 QByteArray action;
155 QByteArray sysname;
156 struct pollfd pollfds[1];
157
158 pollfds[0].fd = udevFd;
159 pollfds[0].events = POLLIN;
160 pollfds[0].revents = 0;
161 ret = poll(fds: pollfds, nfds: 1, timeout: -1);
162
163 if ((pollfds[0].revents & POLLIN) && ret == 1) {
164 device = udev_monitor_receive_device(udev_monitor: udevMonitor);
165 if (device) {
166 subsystem = udev_device_get_subsystem(udev_device: device);
167 action = udev_device_get_action(udev_device: device);
168 sysname = udev_device_get_sysname(udev_device: device);
169
170#if defined(QT_SIMULATOR)
171 if (qstrcmp(subsystem, "block") == 0 && qstrcmp(action, "change") == 0)
172 emit driveChanged();
173#endif
174 if (qstrcmp(str1: subsystem, str2: "block") == 0
175 && ((qstrcmp(str1: action, str2: "add") == 0) || qstrcmp(str1: action, str2: "remove") == 0)) {
176 emit driveChanged();
177 } else if (qstrcmp(str1: subsystem, str2: "power_supply") == 0) {
178 int i = -1;
179 if (sysname.contains(c: "AC")) {
180 bool enabled = false;
181 if (qstrcmp(str1: udev_device_get_sysattr_value(udev_device: device, sysattr: "online"), str2: "1") == 0)
182 enabled = true;
183 emit chargerTypeChanged(value: "AC", enabled);
184 } else if (sysname.contains(c: "USB")) {
185 bool enabled = false;
186 QByteArray charger(udev_device_get_sysattr_value(udev_device: device, sysattr: "type"));
187 if (qstrcmp(str1: udev_device_get_sysattr_value(udev_device: device, sysattr: "present"), str2: "1") == 0)
188 enabled = true;
189 emit chargerTypeChanged(value: charger, enabled);
190 } else if (sysname.contains(c: "BAT")) {
191 bool ok;
192 i = sysname.right(len: 1).toInt(ok: &ok);
193 if (!ok)
194 i = -1;
195 }
196
197 if (i > -1) {
198 QByteArray status(udev_device_get_sysattr_value(udev_device: device, sysattr: "status"));
199 if (!status.isEmpty())
200 emit batteryDataChanged(battery: i, attribute: "status", value: status);
201
202 QByteArray remainingCapacity(udev_device_get_sysattr_value(udev_device: device, sysattr: "charge_now"));
203 if (!remainingCapacity.isEmpty())
204 emit batteryDataChanged(battery: i, attribute: "charge_now", value: remainingCapacity);
205
206 QByteArray remainingChargingTime(udev_device_get_sysattr_value(udev_device: device, sysattr: "time_to_full_avg"));
207 if (!remainingChargingTime.isEmpty())
208 emit batteryDataChanged(battery: i, attribute: "time_to_full_avg", value: remainingChargingTime);
209
210 QByteArray voltage(udev_device_get_sysattr_value(udev_device: device, sysattr: "voltage_now"));
211 if (!voltage.isEmpty())
212 emit batteryDataChanged(battery: i, attribute: "voltage_now", value: voltage);
213
214 QByteArray currentFlow(udev_device_get_sysattr_value(udev_device: device, sysattr: "current_now"));
215 if (!currentFlow.isEmpty())
216 emit batteryDataChanged(battery: i, attribute: "current_now", value: currentFlow);
217
218 QByteArray batteryStatus(udev_device_get_sysattr_value(udev_device: device, sysattr: "capacity_level"));
219 if (!batteryStatus.isEmpty())
220 emit batteryDataChanged(battery: i, attribute: "capacity_level", value: batteryStatus);
221 }
222 }
223 udev_device_unref(udev_device: device);
224 }
225 }
226}
227
228QT_END_NAMESPACE
229
230#endif // QT_NO_UDEV
231

source code of qtsystems/src/systeminfo/linux/qudevwrapper.cpp