2009-07-27 16:40:11 +01:00
|
|
|
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
|
|
|
|
|
*
|
2011-01-04 18:05:09 +00:00
|
|
|
* Copyright (C) 2010 Richard Hughes <richard@hughsie.com>
|
2009-07-27 16:40:11 +01:00
|
|
|
*
|
|
|
|
|
* Licensed under the GNU General Public License Version 2
|
|
|
|
|
*
|
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software
|
2010-01-27 16:27:15 +00:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
2009-07-27 16:40:11 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <math.h>
|
2010-07-07 11:20:47 +02:00
|
|
|
#include <sys/wait.h>
|
2009-07-27 16:40:11 +01:00
|
|
|
#include <glib/gi18n.h>
|
|
|
|
|
#include <gio/gio.h>
|
2017-02-17 13:56:21 +01:00
|
|
|
#include <gio/gunixfdlist.h>
|
2009-07-27 16:40:11 +01:00
|
|
|
#include <gudev/gudev.h>
|
|
|
|
|
|
2010-01-18 12:26:55 +00:00
|
|
|
#include "up-backend.h"
|
2018-06-19 13:41:30 +02:00
|
|
|
#include "up-backend-linux-private.h"
|
2010-01-18 12:26:55 +00:00
|
|
|
#include "up-daemon.h"
|
|
|
|
|
#include "up-device.h"
|
2009-07-27 16:40:11 +01:00
|
|
|
|
2010-01-18 12:26:55 +00:00
|
|
|
#include "up-device-supply.h"
|
|
|
|
|
#include "up-device-wup.h"
|
|
|
|
|
#include "up-device-hid.h"
|
2017-10-20 17:15:53 +02:00
|
|
|
#include "up-device-bluez.h"
|
2010-01-18 12:26:55 +00:00
|
|
|
#include "up-input.h"
|
2011-03-14 11:01:12 +00:00
|
|
|
#include "up-config.h"
|
2010-05-28 01:56:35 +01:00
|
|
|
#ifdef HAVE_IDEVICE
|
|
|
|
|
#include "up-device-idevice.h"
|
|
|
|
|
#endif /* HAVE_IDEVICE */
|
2009-07-27 16:40:11 +01:00
|
|
|
|
2010-01-18 12:32:06 +00:00
|
|
|
static void up_backend_class_init (UpBackendClass *klass);
|
|
|
|
|
static void up_backend_init (UpBackend *backend);
|
|
|
|
|
static void up_backend_finalize (GObject *object);
|
2009-07-27 16:40:11 +01:00
|
|
|
|
2013-10-13 02:46:32 +02:00
|
|
|
#define LOGIND_DBUS_NAME "org.freedesktop.login1"
|
|
|
|
|
#define LOGIND_DBUS_PATH "/org/freedesktop/login1"
|
|
|
|
|
#define LOGIND_DBUS_INTERFACE "org.freedesktop.login1.Manager"
|
|
|
|
|
|
2010-01-18 12:32:06 +00:00
|
|
|
struct UpBackendPrivate
|
2009-07-27 16:40:11 +01:00
|
|
|
{
|
2010-01-18 12:35:47 +00:00
|
|
|
UpDaemon *daemon;
|
2010-01-18 12:49:30 +00:00
|
|
|
UpDeviceList *device_list;
|
2009-07-27 16:40:11 +01:00
|
|
|
GUdevClient *gudev_client;
|
2010-01-18 12:49:30 +00:00
|
|
|
UpDeviceList *managed_devices;
|
2011-03-14 11:01:12 +00:00
|
|
|
UpConfig *config;
|
2013-10-13 02:46:32 +02:00
|
|
|
GDBusProxy *logind_proxy;
|
2017-02-10 15:19:51 +01:00
|
|
|
guint logind_sleep_id;
|
2021-07-08 19:25:21 +02:00
|
|
|
int logind_delay_inhibitor_fd;
|
2017-10-20 17:15:53 +02:00
|
|
|
|
|
|
|
|
/* BlueZ */
|
|
|
|
|
guint bluez_watch_id;
|
|
|
|
|
GDBusObjectManager *bluez_client;
|
2009-07-27 16:40:11 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
SIGNAL_DEVICE_ADDED,
|
|
|
|
|
SIGNAL_DEVICE_REMOVED,
|
|
|
|
|
SIGNAL_LAST
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static guint signals [SIGNAL_LAST] = { 0 };
|
|
|
|
|
|
2019-02-20 17:47:45 +01:00
|
|
|
G_DEFINE_TYPE_WITH_PRIVATE (UpBackend, up_backend, G_TYPE_OBJECT)
|
2009-07-27 16:40:11 +01:00
|
|
|
|
2022-02-11 11:09:47 +01:00
|
|
|
static gboolean up_backend_device_add (UpBackend *backend, GUdevDevice *native, const char *was_event);
|
2010-01-18 12:32:06 +00:00
|
|
|
static void up_backend_device_remove (UpBackend *backend, GUdevDevice *native);
|
2009-07-27 16:40:11 +01:00
|
|
|
|
2020-10-22 15:36:00 +02:00
|
|
|
static void
|
|
|
|
|
input_switch_changed_cb (UpInput *input,
|
|
|
|
|
gboolean switch_value,
|
|
|
|
|
UpBackend *backend)
|
|
|
|
|
{
|
|
|
|
|
up_daemon_set_lid_is_closed (backend->priv->daemon, switch_value);
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-17 10:52:04 +02:00
|
|
|
static gpointer
|
|
|
|
|
is_macbook (gpointer data)
|
|
|
|
|
{
|
2020-09-15 13:08:03 +02:00
|
|
|
g_autofree char *product = NULL;
|
|
|
|
|
|
|
|
|
|
if (!g_file_get_contents ("/sys/devices/virtual/dmi/id/product_name", &product, NULL, NULL) ||
|
|
|
|
|
product == NULL)
|
|
|
|
|
return GINT_TO_POINTER(FALSE);
|
|
|
|
|
return GINT_TO_POINTER(g_str_has_prefix (product, "MacBook"));
|
2021-06-17 10:52:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
|
up_backend_needs_poll_after_uevent (void)
|
|
|
|
|
{
|
|
|
|
|
static GOnce dmi_once = G_ONCE_INIT;
|
|
|
|
|
g_once (&dmi_once, is_macbook, NULL);
|
|
|
|
|
return GPOINTER_TO_INT(dmi_once.retval);
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-18 12:49:30 +00:00
|
|
|
static UpDevice *
|
2010-01-18 12:32:06 +00:00
|
|
|
up_backend_device_new (UpBackend *backend, GUdevDevice *native)
|
2009-07-27 16:40:11 +01:00
|
|
|
{
|
|
|
|
|
const gchar *subsys;
|
|
|
|
|
const gchar *native_path;
|
2010-01-18 12:49:30 +00:00
|
|
|
UpDevice *device = NULL;
|
2010-01-18 13:15:47 +00:00
|
|
|
UpInput *input;
|
2009-07-27 16:40:11 +01:00
|
|
|
gboolean ret;
|
|
|
|
|
|
|
|
|
|
subsys = g_udev_device_get_subsystem (native);
|
|
|
|
|
if (g_strcmp0 (subsys, "power_supply") == 0) {
|
|
|
|
|
|
|
|
|
|
/* are we a valid power supply */
|
2010-01-18 12:49:30 +00:00
|
|
|
device = UP_DEVICE (up_device_supply_new ());
|
2021-06-17 10:52:23 +02:00
|
|
|
g_object_set (G_OBJECT(device),
|
|
|
|
|
"ignore-system-percentage", GPOINTER_TO_INT (is_macbook (NULL)),
|
|
|
|
|
NULL);
|
2010-01-18 12:49:30 +00:00
|
|
|
ret = up_device_coldplug (device, backend->priv->daemon, G_OBJECT (native));
|
2009-07-27 16:40:11 +01:00
|
|
|
if (ret)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
/* no valid power supply object */
|
2017-10-19 19:14:59 +02:00
|
|
|
g_clear_object (&device);
|
2009-07-27 16:40:11 +01:00
|
|
|
|
|
|
|
|
} else if (g_strcmp0 (subsys, "tty") == 0) {
|
|
|
|
|
|
2013-10-12 14:55:30 +02:00
|
|
|
/* see if this is a Watts Up Pro device */
|
|
|
|
|
device = UP_DEVICE (up_device_wup_new ());
|
|
|
|
|
ret = up_device_coldplug (device, backend->priv->daemon, G_OBJECT (native));
|
|
|
|
|
if (ret)
|
|
|
|
|
goto out;
|
2009-07-27 16:40:11 +01:00
|
|
|
|
2009-09-11 12:05:16 +01:00
|
|
|
/* no valid TTY object */
|
2017-10-19 19:14:59 +02:00
|
|
|
g_clear_object (&device);
|
2009-07-27 16:40:11 +01:00
|
|
|
|
Fix device matching for recent kernels
In recent kernels, hiddev* devices now have class "usbmisc", rather
than "usb" (see http://www.spinics.net/lists/linux-usb/msg62276.html).
This change translates into a change in SUBSYSTEM matching for hiddev*
devices. This fix addresses this for recent kernels while retaining
existing behavior. For reference, here is an attribute-walk for a
CyberPower CPS 1500C on kernel 3.7.0:
[Ubuntu bug #1091702: udev rules fail to match hid devices with new kernels]
udevadm info --attribute-walk --path=/devices/pci0000:00/0000:00:1d.2/usb4/4-1/4-1:1.0/usbmisc/hiddev0
Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.
looking at device '/devices/pci0000:00/0000:00:1d.2/usb4/4-1/4-1:1.0/usbmisc/hiddev0':
KERNEL=="hiddev0"
SUBSYSTEM=="usbmisc"
DRIVER==""
looking at parent device '/devices/pci0000:00/0000:00:1d.2/usb4/4-1/4-1:1.0':
KERNELS=="4-1:1.0"
SUBSYSTEMS=="usb"
DRIVERS=="usbhid"
ATTRS{bInterfaceClass}=="03"
ATTRS{bInterfaceSubClass}=="00"
ATTRS{bInterfaceProtocol}=="00"
ATTRS{bNumEndpoints}=="01"
ATTRS{supports_autosuspend}=="1"
ATTRS{bAlternateSetting}==" 0"
ATTRS{bInterfaceNumber}=="00"
looking at parent device '/devices/pci0000:00/0000:00:1d.2/usb4/4-1':
KERNELS=="4-1"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{bDeviceSubClass}=="00"
ATTRS{bDeviceProtocol}=="00"
ATTRS{devpath}=="1"
ATTRS{idVendor}=="0764"
ATTRS{speed}=="1.5"
ATTRS{bNumInterfaces}==" 1"
ATTRS{bConfigurationValue}=="1"
ATTRS{bMaxPacketSize0}=="8"
ATTRS{busnum}=="4"
ATTRS{devnum}=="2"
ATTRS{configuration}==""
ATTRS{bMaxPower}==" 50mA"
ATTRS{authorized}=="1"
ATTRS{bmAttributes}=="c0"
ATTRS{bNumConfigurations}=="1"
ATTRS{maxchild}=="0"
ATTRS{bcdDevice}=="0001"
ATTRS{avoid_reset_quirk}=="0"
ATTRS{quirks}=="0x0"
ATTRS{version}==" 1.10"
ATTRS{urbnum}=="36"
ATTRS{ltm_capable}=="no"
ATTRS{manufacturer}=="CPS"
ATTRS{removable}=="unknown"
ATTRS{idProduct}=="0501"
ATTRS{bDeviceClass}=="00"
ATTRS{product}==" CP 1500C"
looking at parent device '/devices/pci0000:00/0000:00:1d.2/usb4':
KERNELS=="usb4"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{bDeviceSubClass}=="00"
ATTRS{bDeviceProtocol}=="00"
ATTRS{devpath}=="0"
ATTRS{idVendor}=="1d6b"
ATTRS{speed}=="12"
ATTRS{bNumInterfaces}==" 1"
ATTRS{bConfigurationValue}=="1"
ATTRS{bMaxPacketSize0}=="64"
ATTRS{authorized_default}=="1"
ATTRS{busnum}=="4"
ATTRS{devnum}=="1"
ATTRS{configuration}==""
ATTRS{bMaxPower}==" 0mA"
ATTRS{authorized}=="1"
ATTRS{bmAttributes}=="e0"
ATTRS{bNumConfigurations}=="1"
ATTRS{maxchild}=="2"
ATTRS{bcdDevice}=="0307"
ATTRS{avoid_reset_quirk}=="0"
ATTRS{quirks}=="0x0"
ATTRS{serial}=="0000:00:1d.2"
ATTRS{version}==" 1.10"
ATTRS{urbnum}=="50"
ATTRS{ltm_capable}=="no"
ATTRS{manufacturer}=="Linux 3.7.0-030700-generic uhci_hcd"
ATTRS{removable}=="unknown"
ATTRS{idProduct}=="0001"
ATTRS{bDeviceClass}=="09"
ATTRS{product}=="UHCI Host Controller"
looking at parent device '/devices/pci0000:00/0000:00:1d.2':
KERNELS=="0000:00:1d.2"
SUBSYSTEMS=="pci"
DRIVERS=="uhci_hcd"
ATTRS{irq}=="18"
ATTRS{subsystem_vendor}=="0x1028"
ATTRS{broken_parity_status}=="0"
ATTRS{class}=="0x0c0300"
ATTRS{consistent_dma_mask_bits}=="32"
ATTRS{dma_mask_bits}=="32"
ATTRS{local_cpus}=="00000000,00000000,00000000,00000000,00000000,00000000,00000000,000000ff"
ATTRS{device}=="0x268a"
ATTRS{msi_bus}==""
ATTRS{local_cpulist}=="0-7"
ATTRS{vendor}=="0x8086"
ATTRS{subsystem_device}=="0x021e"
ATTRS{numa_node}=="-1"
ATTRS{d3cold_allowed}=="0"
looking at parent device '/devices/pci0000:00':
KERNELS=="pci0000:00"
SUBSYSTEMS==""
DRIVERS==""
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Richard Hughes <richard@hughsie.com>
2012-12-23 15:45:01 -05:00
|
|
|
} else if (g_strcmp0 (subsys, "usb") == 0 || g_strcmp0 (subsys, "usbmisc") == 0) {
|
2009-07-27 16:40:11 +01:00
|
|
|
|
2010-05-28 01:56:35 +01:00
|
|
|
#ifdef HAVE_IDEVICE
|
|
|
|
|
/* see if this is an iDevice */
|
|
|
|
|
device = UP_DEVICE (up_device_idevice_new ());
|
|
|
|
|
ret = up_device_coldplug (device, backend->priv->daemon, G_OBJECT (native));
|
|
|
|
|
if (ret)
|
|
|
|
|
goto out;
|
|
|
|
|
g_object_unref (device);
|
|
|
|
|
#endif /* HAVE_IDEVICE */
|
|
|
|
|
|
2009-07-27 16:40:11 +01:00
|
|
|
/* try to detect a HID UPS */
|
2010-01-18 12:49:30 +00:00
|
|
|
device = UP_DEVICE (up_device_hid_new ());
|
|
|
|
|
ret = up_device_coldplug (device, backend->priv->daemon, G_OBJECT (native));
|
2009-07-27 16:40:11 +01:00
|
|
|
if (ret)
|
|
|
|
|
goto out;
|
|
|
|
|
|
2009-09-11 12:05:16 +01:00
|
|
|
/* no valid USB object */
|
2017-10-19 19:14:59 +02:00
|
|
|
g_clear_object (&device);
|
2009-07-27 16:40:11 +01:00
|
|
|
|
|
|
|
|
} else if (g_strcmp0 (subsys, "input") == 0) {
|
|
|
|
|
|
|
|
|
|
/* check input device */
|
2010-01-18 13:15:47 +00:00
|
|
|
input = up_input_new ();
|
2020-10-22 15:36:00 +02:00
|
|
|
ret = up_input_coldplug (input, native);
|
2012-08-07 00:11:19 +02:00
|
|
|
if (ret) {
|
|
|
|
|
/* we now have a lid */
|
|
|
|
|
up_daemon_set_lid_is_present (backend->priv->daemon, TRUE);
|
2020-10-22 15:36:00 +02:00
|
|
|
g_signal_connect (G_OBJECT (input), "switch-changed",
|
|
|
|
|
G_CALLBACK (input_switch_changed_cb), backend);
|
|
|
|
|
up_daemon_set_lid_is_closed (backend->priv->daemon,
|
|
|
|
|
up_input_get_switch_value (input));
|
2009-07-27 16:40:11 +01:00
|
|
|
|
2020-10-22 14:09:08 +02:00
|
|
|
/* not a power device, add it to the managed devices
|
|
|
|
|
* and don't return a power device */
|
2012-08-07 00:11:19 +02:00
|
|
|
up_device_list_insert (backend->priv->managed_devices, G_OBJECT (native), G_OBJECT (input));
|
|
|
|
|
device = NULL;
|
|
|
|
|
}
|
2013-01-09 10:28:58 +00:00
|
|
|
g_object_unref (input);
|
2009-07-27 16:40:11 +01:00
|
|
|
} else {
|
|
|
|
|
native_path = g_udev_device_get_sysfs_path (native);
|
2010-11-01 11:28:31 +00:00
|
|
|
g_warning ("native path %s (%s) ignoring", native_path, subsys);
|
2009-07-27 16:40:11 +01:00
|
|
|
}
|
|
|
|
|
out:
|
|
|
|
|
return device;
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-11 12:05:16 +01:00
|
|
|
static void
|
2022-02-11 11:09:47 +01:00
|
|
|
up_backend_device_changed (UpBackend *backend, GUdevDevice *native, const char *was_event)
|
2009-09-11 12:05:16 +01:00
|
|
|
{
|
|
|
|
|
GObject *object;
|
2010-01-18 12:49:30 +00:00
|
|
|
UpDevice *device;
|
2009-09-11 12:05:16 +01:00
|
|
|
gboolean ret;
|
|
|
|
|
|
|
|
|
|
/* first, check the device and add it if it doesn't exist */
|
2010-01-18 12:49:30 +00:00
|
|
|
object = up_device_list_lookup (backend->priv->device_list, G_OBJECT (native));
|
2009-09-11 12:05:16 +01:00
|
|
|
if (object == NULL) {
|
2022-02-11 11:09:47 +01:00
|
|
|
up_backend_device_add (backend, native, "changed");
|
2009-09-11 12:05:16 +01:00
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* need to refresh device */
|
2010-01-18 12:49:30 +00:00
|
|
|
device = UP_DEVICE (object);
|
|
|
|
|
ret = up_device_refresh_internal (device);
|
2009-09-11 12:05:16 +01:00
|
|
|
if (!ret) {
|
2010-11-01 11:28:31 +00:00
|
|
|
g_debug ("no changes on %s", up_device_get_object_path (device));
|
2009-09-11 12:05:16 +01:00
|
|
|
goto out;
|
|
|
|
|
}
|
2022-02-11 11:09:47 +01:00
|
|
|
|
|
|
|
|
if (was_event)
|
|
|
|
|
g_warning ("treated %s event as change on %s", was_event, g_udev_device_get_sysfs_path (native));
|
|
|
|
|
|
2009-09-11 12:05:16 +01:00
|
|
|
out:
|
2017-10-19 19:14:59 +02:00
|
|
|
g_clear_object (&object);
|
2009-09-11 12:05:16 +01:00
|
|
|
}
|
|
|
|
|
|
2009-07-27 16:40:11 +01:00
|
|
|
static gboolean
|
2022-02-11 11:09:47 +01:00
|
|
|
up_backend_device_add (UpBackend *backend, GUdevDevice *native, const char *was_event)
|
2009-07-27 16:40:11 +01:00
|
|
|
{
|
|
|
|
|
GObject *object;
|
2010-01-18 12:49:30 +00:00
|
|
|
UpDevice *device;
|
2009-07-27 16:40:11 +01:00
|
|
|
gboolean ret = TRUE;
|
|
|
|
|
|
|
|
|
|
/* does device exist in db? */
|
2010-01-18 12:49:30 +00:00
|
|
|
object = up_device_list_lookup (backend->priv->device_list, G_OBJECT (native));
|
2009-07-27 16:40:11 +01:00
|
|
|
if (object != NULL) {
|
2010-01-18 12:49:30 +00:00
|
|
|
device = UP_DEVICE (object);
|
2009-07-27 16:40:11 +01:00
|
|
|
/* we already have the device; treat as change event */
|
2022-02-11 11:09:47 +01:00
|
|
|
up_backend_device_changed (backend, native, "add");
|
2009-07-27 16:40:11 +01:00
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* get the right sort of device */
|
2010-01-18 12:32:06 +00:00
|
|
|
device = up_backend_device_new (backend, native);
|
2009-07-27 16:40:11 +01:00
|
|
|
if (device == NULL) {
|
|
|
|
|
ret = FALSE;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-11 11:09:47 +01:00
|
|
|
if (was_event)
|
|
|
|
|
g_warning ("treated %s event as add on %s", was_event, g_udev_device_get_sysfs_path (native));
|
|
|
|
|
|
2009-07-27 16:40:11 +01:00
|
|
|
/* emit */
|
2009-09-11 12:05:16 +01:00
|
|
|
g_signal_emit (backend, signals[SIGNAL_DEVICE_ADDED], 0, native, device);
|
2009-07-27 16:40:11 +01:00
|
|
|
out:
|
2017-10-19 19:14:59 +02:00
|
|
|
g_clear_object (&object);
|
2009-07-27 16:40:11 +01:00
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2010-01-18 12:32:06 +00:00
|
|
|
up_backend_device_remove (UpBackend *backend, GUdevDevice *native)
|
2009-07-27 16:40:11 +01:00
|
|
|
{
|
|
|
|
|
GObject *object;
|
2010-01-18 12:49:30 +00:00
|
|
|
UpDevice *device;
|
2009-07-27 16:40:11 +01:00
|
|
|
|
|
|
|
|
/* does device exist in db? */
|
2010-01-18 12:49:30 +00:00
|
|
|
object = up_device_list_lookup (backend->priv->device_list, G_OBJECT (native));
|
2009-07-27 16:40:11 +01:00
|
|
|
if (object == NULL) {
|
2010-11-01 11:28:31 +00:00
|
|
|
g_debug ("ignoring remove event on %s", g_udev_device_get_sysfs_path (native));
|
2009-09-11 12:34:25 +01:00
|
|
|
goto out;
|
2009-07-27 16:40:11 +01:00
|
|
|
}
|
2009-09-11 12:34:25 +01:00
|
|
|
|
2010-01-18 12:49:30 +00:00
|
|
|
device = UP_DEVICE (object);
|
2009-09-11 12:34:25 +01:00
|
|
|
/* emit */
|
2010-11-01 11:28:31 +00:00
|
|
|
g_debug ("emitting device-removed: %s", g_udev_device_get_sysfs_path (native));
|
2009-09-11 12:34:25 +01:00
|
|
|
g_signal_emit (backend, signals[SIGNAL_DEVICE_REMOVED], 0, native, device);
|
|
|
|
|
|
|
|
|
|
out:
|
2017-10-19 19:14:59 +02:00
|
|
|
g_clear_object (&object);
|
2009-07-27 16:40:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2010-01-18 12:32:06 +00:00
|
|
|
up_backend_uevent_signal_handler_cb (GUdevClient *client, const gchar *action,
|
2009-07-27 16:40:11 +01:00
|
|
|
GUdevDevice *device, gpointer user_data)
|
|
|
|
|
{
|
2010-01-18 12:32:06 +00:00
|
|
|
UpBackend *backend = UP_BACKEND (user_data);
|
2009-07-27 16:40:11 +01:00
|
|
|
|
|
|
|
|
if (g_strcmp0 (action, "add") == 0) {
|
2010-11-01 11:28:31 +00:00
|
|
|
g_debug ("SYSFS add %s", g_udev_device_get_sysfs_path (device));
|
2022-02-11 11:09:47 +01:00
|
|
|
up_backend_device_add (backend, device, NULL);
|
2009-07-27 16:40:11 +01:00
|
|
|
} else if (g_strcmp0 (action, "remove") == 0) {
|
2010-11-01 11:28:31 +00:00
|
|
|
g_debug ("SYSFS remove %s", g_udev_device_get_sysfs_path (device));
|
2010-01-18 12:32:06 +00:00
|
|
|
up_backend_device_remove (backend, device);
|
2009-07-27 16:40:11 +01:00
|
|
|
} else if (g_strcmp0 (action, "change") == 0) {
|
2010-11-01 11:28:31 +00:00
|
|
|
g_debug ("SYSFS change %s", g_udev_device_get_sysfs_path (device));
|
2022-02-11 11:09:47 +01:00
|
|
|
up_backend_device_changed (backend, device, NULL);
|
2009-07-27 16:40:11 +01:00
|
|
|
} else {
|
2018-04-06 11:46:28 -07:00
|
|
|
g_debug ("unhandled action '%s' on %s", action, g_udev_device_get_sysfs_path (device));
|
2009-07-27 16:40:11 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-20 17:15:53 +02:00
|
|
|
static gboolean
|
|
|
|
|
is_battery_iface_proxy (GDBusProxy *interface_proxy)
|
|
|
|
|
{
|
|
|
|
|
const char *iface;
|
|
|
|
|
|
|
|
|
|
iface = g_dbus_proxy_get_interface_name (interface_proxy);
|
|
|
|
|
return g_str_equal (iface, "org.bluez.Battery1");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
has_battery_iface (GDBusObject *object)
|
|
|
|
|
{
|
|
|
|
|
GDBusInterface *iface;
|
|
|
|
|
|
|
|
|
|
iface = g_dbus_object_get_interface (object, "org.bluez.Battery1");
|
|
|
|
|
if (!iface)
|
|
|
|
|
return FALSE;
|
|
|
|
|
g_object_unref (iface);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
bluez_proxies_changed (GDBusObjectManagerClient *manager,
|
|
|
|
|
GDBusObjectProxy *object_proxy,
|
|
|
|
|
GDBusProxy *interface_proxy,
|
|
|
|
|
GVariant *changed_properties,
|
|
|
|
|
GStrv invalidated_properties,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
UpBackend *backend = user_data;
|
|
|
|
|
GObject *object;
|
|
|
|
|
UpDeviceBluez *bluez;
|
|
|
|
|
|
|
|
|
|
if (!is_battery_iface_proxy (interface_proxy))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
object = up_device_list_lookup (backend->priv->device_list, G_OBJECT (object_proxy));
|
|
|
|
|
if (!object)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
bluez = UP_DEVICE_BLUEZ (object);
|
|
|
|
|
up_device_bluez_update (bluez, changed_properties);
|
|
|
|
|
g_object_unref (object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
bluez_interface_removed (GDBusObjectManager *manager,
|
|
|
|
|
GDBusObject *bus_object,
|
|
|
|
|
GDBusInterface *interface,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
UpBackend *backend = user_data;
|
|
|
|
|
GObject *object;
|
|
|
|
|
|
|
|
|
|
/* It might be another iface on another device that got removed */
|
|
|
|
|
if (has_battery_iface (bus_object))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
object = up_device_list_lookup (backend->priv->device_list, G_OBJECT (bus_object));
|
|
|
|
|
if (!object)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
g_debug ("emitting device-removed: %s", g_dbus_object_get_object_path (bus_object));
|
|
|
|
|
g_signal_emit (backend, signals[SIGNAL_DEVICE_REMOVED], 0, bus_object, UP_DEVICE (object));
|
|
|
|
|
|
|
|
|
|
g_object_unref (object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
bluez_interface_added (GDBusObjectManager *manager,
|
|
|
|
|
GDBusObject *bus_object,
|
|
|
|
|
GDBusInterface *interface,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
UpBackend *backend = user_data;
|
|
|
|
|
UpDevice *device;
|
|
|
|
|
GObject *object;
|
|
|
|
|
gboolean ret;
|
|
|
|
|
|
|
|
|
|
if (!has_battery_iface (bus_object))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
object = up_device_list_lookup (backend->priv->device_list, G_OBJECT (bus_object));
|
|
|
|
|
if (object != NULL) {
|
|
|
|
|
g_object_unref (object);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
device = UP_DEVICE (up_device_bluez_new ());
|
|
|
|
|
ret = up_device_coldplug (device, backend->priv->daemon, G_OBJECT (bus_object));
|
|
|
|
|
if (!ret) {
|
|
|
|
|
g_object_unref (device);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_debug ("emitting device-added: %s", g_dbus_object_get_object_path (bus_object));
|
|
|
|
|
g_signal_emit (backend, signals[SIGNAL_DEVICE_ADDED], 0, bus_object, device);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
bluez_appeared (GDBusConnection *connection,
|
|
|
|
|
const gchar *name,
|
|
|
|
|
const gchar *name_owner,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
UpBackend *backend = user_data;
|
|
|
|
|
GError *error = NULL;
|
|
|
|
|
GList *objects, *l;
|
|
|
|
|
|
|
|
|
|
g_assert (backend->priv->bluez_client == NULL);
|
|
|
|
|
|
|
|
|
|
backend->priv->bluez_client = g_dbus_object_manager_client_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
|
|
|
|
|
G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START,
|
|
|
|
|
"org.bluez",
|
|
|
|
|
"/",
|
|
|
|
|
NULL, NULL, NULL,
|
|
|
|
|
NULL, &error);
|
|
|
|
|
if (!backend->priv->bluez_client) {
|
|
|
|
|
g_warning ("Failed to create object manager for BlueZ: %s",
|
|
|
|
|
error->message);
|
|
|
|
|
g_error_free (error);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_debug ("BlueZ appeared");
|
|
|
|
|
|
|
|
|
|
g_signal_connect (backend->priv->bluez_client, "interface-proxy-properties-changed",
|
|
|
|
|
G_CALLBACK (bluez_proxies_changed), backend);
|
|
|
|
|
g_signal_connect (backend->priv->bluez_client, "interface-removed",
|
|
|
|
|
G_CALLBACK (bluez_interface_removed), backend);
|
|
|
|
|
g_signal_connect (backend->priv->bluez_client, "interface-added",
|
|
|
|
|
G_CALLBACK (bluez_interface_added), backend);
|
|
|
|
|
|
|
|
|
|
objects = g_dbus_object_manager_get_objects (backend->priv->bluez_client);
|
|
|
|
|
for (l = objects; l != NULL; l = l->next) {
|
|
|
|
|
GDBusObject *object = l->data;
|
|
|
|
|
GList *interfaces, *k;
|
|
|
|
|
|
|
|
|
|
interfaces = g_dbus_object_get_interfaces (object);
|
|
|
|
|
|
|
|
|
|
for (k = interfaces; k != NULL; k = k->next) {
|
|
|
|
|
GDBusInterface *iface = k->data;
|
|
|
|
|
|
|
|
|
|
bluez_interface_added (backend->priv->bluez_client,
|
|
|
|
|
object,
|
|
|
|
|
iface,
|
|
|
|
|
backend);
|
|
|
|
|
g_object_unref (iface);
|
|
|
|
|
}
|
|
|
|
|
g_list_free (interfaces);
|
|
|
|
|
g_object_unref (object);
|
|
|
|
|
}
|
|
|
|
|
g_list_free (objects);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
bluez_vanished (GDBusConnection *connection,
|
|
|
|
|
const gchar *name,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
UpBackend *backend = user_data;
|
|
|
|
|
GPtrArray *array;
|
|
|
|
|
guint i;
|
|
|
|
|
|
|
|
|
|
g_debug ("BlueZ disappeared");
|
|
|
|
|
|
|
|
|
|
array = up_device_list_get_array (backend->priv->device_list);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < array->len; i++) {
|
|
|
|
|
UpDevice *device = UP_DEVICE (g_ptr_array_index (array, i));
|
|
|
|
|
if (UP_IS_DEVICE_BLUEZ (device)) {
|
|
|
|
|
GDBusObject *object;
|
|
|
|
|
|
|
|
|
|
object = G_DBUS_OBJECT (up_device_get_native (device));
|
|
|
|
|
g_debug ("emitting device-removed: %s", g_dbus_object_get_object_path (object));
|
|
|
|
|
g_signal_emit (backend, signals[SIGNAL_DEVICE_REMOVED], 0, object, UP_DEVICE (object));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_ptr_array_unref (array);
|
|
|
|
|
|
|
|
|
|
g_clear_object (&backend->priv->bluez_client);
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-27 16:40:11 +01:00
|
|
|
/**
|
2010-01-18 12:32:06 +00:00
|
|
|
* up_backend_coldplug:
|
|
|
|
|
* @backend: The %UpBackend class instance
|
2010-01-18 12:35:47 +00:00
|
|
|
* @daemon: The %UpDaemon controlling instance
|
2009-07-27 16:40:11 +01:00
|
|
|
*
|
|
|
|
|
* Finds all the devices already plugged in, and emits device-add signals for
|
|
|
|
|
* each of them.
|
|
|
|
|
*
|
|
|
|
|
* Return value: %TRUE for success
|
|
|
|
|
**/
|
|
|
|
|
gboolean
|
2010-01-18 12:35:47 +00:00
|
|
|
up_backend_coldplug (UpBackend *backend, UpDaemon *daemon)
|
2009-07-27 16:40:11 +01:00
|
|
|
{
|
|
|
|
|
GUdevDevice *native;
|
|
|
|
|
GList *devices;
|
|
|
|
|
GList *l;
|
|
|
|
|
guint i;
|
2021-06-17 11:54:22 +02:00
|
|
|
const gchar *subsystems_wup[] = {"power_supply", "usb", "usbmisc", "tty", "input", NULL};
|
|
|
|
|
const gchar *subsystems[] = {"power_supply", "usb", "usbmisc", "input", NULL};
|
2009-07-27 16:40:11 +01:00
|
|
|
|
|
|
|
|
backend->priv->daemon = g_object_ref (daemon);
|
2010-01-18 12:35:47 +00:00
|
|
|
backend->priv->device_list = up_daemon_get_device_list (daemon);
|
2013-10-12 14:55:30 +02:00
|
|
|
if (up_config_get_boolean (backend->priv->config, "EnableWattsUpPro"))
|
|
|
|
|
backend->priv->gudev_client = g_udev_client_new (subsystems_wup);
|
|
|
|
|
else
|
|
|
|
|
backend->priv->gudev_client = g_udev_client_new (subsystems);
|
2009-09-11 09:58:46 +01:00
|
|
|
g_signal_connect (backend->priv->gudev_client, "uevent",
|
2010-01-18 12:32:06 +00:00
|
|
|
G_CALLBACK (up_backend_uevent_signal_handler_cb), backend);
|
2009-07-27 16:40:11 +01:00
|
|
|
|
|
|
|
|
/* add all subsystems */
|
|
|
|
|
for (i=0; subsystems[i] != NULL; i++) {
|
2010-11-01 11:28:31 +00:00
|
|
|
g_debug ("registering subsystem : %s", subsystems[i]);
|
2009-07-27 16:40:11 +01:00
|
|
|
devices = g_udev_client_query_by_subsystem (backend->priv->gudev_client, subsystems[i]);
|
|
|
|
|
for (l = devices; l != NULL; l = l->next) {
|
|
|
|
|
native = l->data;
|
2022-02-11 11:09:47 +01:00
|
|
|
up_backend_device_add (backend, native, NULL);
|
2009-07-27 16:40:11 +01:00
|
|
|
}
|
2014-06-24 16:41:48 +02:00
|
|
|
g_list_free_full (devices, (GDestroyNotify) g_object_unref);
|
2009-07-27 16:40:11 +01:00
|
|
|
}
|
|
|
|
|
|
2017-10-20 17:15:53 +02:00
|
|
|
backend->priv->bluez_watch_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM,
|
|
|
|
|
"org.bluez",
|
|
|
|
|
G_BUS_NAME_WATCHER_FLAGS_NONE,
|
|
|
|
|
bluez_appeared,
|
|
|
|
|
bluez_vanished,
|
|
|
|
|
backend,
|
|
|
|
|
NULL);
|
|
|
|
|
|
2009-07-27 16:40:11 +01:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-20 15:55:37 +01:00
|
|
|
/**
|
|
|
|
|
* up_backend_unplug:
|
|
|
|
|
* @backend: The %UpBackend class instance
|
|
|
|
|
*
|
|
|
|
|
* Forget about all learned devices, effectively undoing up_backend_coldplug.
|
|
|
|
|
* Resources are released without emitting signals.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
up_backend_unplug (UpBackend *backend)
|
|
|
|
|
{
|
2017-10-19 19:14:59 +02:00
|
|
|
g_clear_object (&backend->priv->gudev_client);
|
|
|
|
|
g_clear_object (&backend->priv->device_list);
|
2014-11-20 15:55:37 +01:00
|
|
|
/* set in init, clear the list to remove reference to UpDaemon */
|
|
|
|
|
if (backend->priv->managed_devices != NULL)
|
|
|
|
|
up_device_list_clear (backend->priv->managed_devices, FALSE);
|
2017-10-19 19:14:59 +02:00
|
|
|
g_clear_object (&backend->priv->daemon);
|
2017-10-20 17:15:53 +02:00
|
|
|
if (backend->priv->bluez_watch_id > 0) {
|
|
|
|
|
g_bus_unwatch_name (backend->priv->bluez_watch_id);
|
|
|
|
|
backend->priv->bluez_watch_id = 0;
|
|
|
|
|
}
|
|
|
|
|
g_clear_object (&backend->priv->bluez_client);
|
2014-11-20 15:55:37 +01:00
|
|
|
}
|
|
|
|
|
|
2013-10-13 02:46:32 +02:00
|
|
|
static gboolean
|
|
|
|
|
check_action_result (GVariant *result)
|
|
|
|
|
{
|
|
|
|
|
if (result) {
|
|
|
|
|
const char *s;
|
|
|
|
|
|
2014-11-06 18:29:07 +01:00
|
|
|
g_variant_get (result, "(&s)", &s);
|
2013-10-17 08:56:41 +02:00
|
|
|
if (g_strcmp0 (s, "yes") == 0)
|
2013-10-13 02:46:32 +02:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2013-10-17 09:04:03 +02:00
|
|
|
* up_backend_get_critical_action:
|
2013-10-13 02:46:32 +02:00
|
|
|
* @backend: The %UpBackend class instance
|
|
|
|
|
*
|
2013-10-17 09:04:03 +02:00
|
|
|
* Which action will be taken when %UP_DEVICE_LEVEL_ACTION
|
|
|
|
|
* warning-level occurs.
|
2013-10-13 02:46:32 +02:00
|
|
|
**/
|
2013-10-17 09:04:03 +02:00
|
|
|
const char *
|
|
|
|
|
up_backend_get_critical_action (UpBackend *backend)
|
2013-10-13 02:46:32 +02:00
|
|
|
{
|
|
|
|
|
struct {
|
|
|
|
|
const gchar *method;
|
|
|
|
|
const gchar *can_method;
|
|
|
|
|
} actions[] = {
|
|
|
|
|
{ "HybridSleep", "CanHybridSleep" },
|
|
|
|
|
{ "Hibernate", "CanHibernate" },
|
|
|
|
|
{ "PowerOff", NULL },
|
|
|
|
|
};
|
2014-08-25 17:04:55 +02:00
|
|
|
guint i = 0;
|
|
|
|
|
char *action;
|
2013-10-13 02:46:32 +02:00
|
|
|
|
2013-10-29 12:51:23 +00:00
|
|
|
g_return_val_if_fail (backend->priv->logind_proxy != NULL, NULL);
|
2013-10-13 02:46:32 +02:00
|
|
|
|
2014-08-25 17:04:55 +02:00
|
|
|
/* Find the configured action first */
|
|
|
|
|
action = up_config_get_string (backend->priv->config, "CriticalPowerAction");
|
|
|
|
|
if (action != NULL) {
|
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (actions); i++)
|
|
|
|
|
if (g_str_equal (actions[i].method, action))
|
|
|
|
|
break;
|
|
|
|
|
if (i >= G_N_ELEMENTS (actions))
|
|
|
|
|
i = 0;
|
|
|
|
|
g_free (action);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (; i < G_N_ELEMENTS (actions); i++) {
|
2013-10-13 02:46:32 +02:00
|
|
|
GVariant *result;
|
|
|
|
|
|
|
|
|
|
if (actions[i].can_method) {
|
2013-10-17 09:04:03 +02:00
|
|
|
gboolean action_available;
|
|
|
|
|
|
2013-10-13 02:46:32 +02:00
|
|
|
/* Check whether we can use the method */
|
|
|
|
|
result = g_dbus_proxy_call_sync (backend->priv->logind_proxy,
|
|
|
|
|
actions[i].can_method,
|
|
|
|
|
NULL,
|
|
|
|
|
G_DBUS_CALL_FLAGS_NONE,
|
|
|
|
|
-1, NULL, NULL);
|
|
|
|
|
action_available = check_action_result (result);
|
|
|
|
|
g_variant_unref (result);
|
|
|
|
|
|
|
|
|
|
if (!action_available)
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-17 09:04:03 +02:00
|
|
|
return actions[i].method;
|
2013-10-13 02:46:32 +02:00
|
|
|
}
|
|
|
|
|
g_assert_not_reached ();
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-17 09:04:03 +02:00
|
|
|
/**
|
|
|
|
|
* up_backend_take_action:
|
|
|
|
|
* @backend: The %UpBackend class instance
|
|
|
|
|
*
|
|
|
|
|
* Act upon the %UP_DEVICE_LEVEL_ACTION warning-level.
|
|
|
|
|
**/
|
|
|
|
|
void
|
|
|
|
|
up_backend_take_action (UpBackend *backend)
|
|
|
|
|
{
|
|
|
|
|
const char *method;
|
|
|
|
|
|
|
|
|
|
method = up_backend_get_critical_action (backend);
|
|
|
|
|
g_assert (method != NULL);
|
|
|
|
|
|
|
|
|
|
/* Take action */
|
|
|
|
|
g_debug ("About to call logind method %s", method);
|
|
|
|
|
g_dbus_proxy_call (backend->priv->logind_proxy,
|
|
|
|
|
method,
|
|
|
|
|
g_variant_new ("(b)", FALSE),
|
|
|
|
|
G_DBUS_CALL_FLAGS_NONE,
|
|
|
|
|
G_MAXINT,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-17 13:56:21 +01:00
|
|
|
/**
|
|
|
|
|
* up_backend_inhibitor_lock_take:
|
|
|
|
|
* @backend: The %UpBackend class instance
|
2021-07-08 19:25:21 +02:00
|
|
|
* @reason: Why the inhibitor lock is taken
|
|
|
|
|
* @mode: The mode of the lock ('delay' or 'block')
|
2017-02-17 13:56:21 +01:00
|
|
|
*
|
2021-07-08 19:25:21 +02:00
|
|
|
* Acquire a sleep inhibitor lock via systemd's logind that will
|
|
|
|
|
* inhibit going to sleep until the lock is released again by
|
|
|
|
|
* closing the file descriptor.
|
2017-02-17 13:56:21 +01:00
|
|
|
*/
|
2021-07-08 19:25:21 +02:00
|
|
|
int
|
|
|
|
|
up_backend_inhibitor_lock_take (UpBackend *backend,
|
|
|
|
|
const char *reason,
|
|
|
|
|
const char *mode)
|
2017-02-17 13:56:21 +01:00
|
|
|
{
|
|
|
|
|
GVariant *out, *input;
|
2017-08-03 17:12:50 +02:00
|
|
|
GUnixFDList *fds = NULL;
|
2021-07-08 19:25:21 +02:00
|
|
|
int fd;
|
2017-02-17 13:56:21 +01:00
|
|
|
GError *error = NULL;
|
|
|
|
|
|
2021-07-08 19:25:21 +02:00
|
|
|
g_return_val_if_fail (reason != NULL, -1);
|
|
|
|
|
g_return_val_if_fail (mode != NULL, -1);
|
|
|
|
|
g_return_val_if_fail (g_str_equal (mode, "delay") || g_str_equal (mode, "block"), -1);
|
2017-02-17 13:56:21 +01:00
|
|
|
|
|
|
|
|
input = g_variant_new ("(ssss)",
|
2021-07-08 19:25:21 +02:00
|
|
|
"sleep", /* what */
|
|
|
|
|
"UPower", /* who */
|
|
|
|
|
reason, /* why */
|
|
|
|
|
mode); /* mode */
|
2017-02-17 13:56:21 +01:00
|
|
|
|
|
|
|
|
out = g_dbus_proxy_call_with_unix_fd_list_sync (backend->priv->logind_proxy,
|
|
|
|
|
"Inhibit",
|
|
|
|
|
input,
|
|
|
|
|
G_DBUS_CALL_FLAGS_NONE,
|
|
|
|
|
-1,
|
|
|
|
|
NULL,
|
|
|
|
|
&fds,
|
|
|
|
|
NULL,
|
|
|
|
|
&error);
|
|
|
|
|
if (out == NULL) {
|
2018-04-12 22:32:13 +02:00
|
|
|
g_warning ("Could not acquire inhibitor lock: %s",
|
|
|
|
|
error ? error->message : "Unknown reason");
|
2018-04-12 22:34:04 +02:00
|
|
|
g_clear_error (&error);
|
2021-07-08 19:25:21 +02:00
|
|
|
return -1;
|
2017-02-17 13:56:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (g_unix_fd_list_get_length (fds) != 1) {
|
|
|
|
|
g_warning ("Unexpected values returned by logind's 'Inhibit'");
|
|
|
|
|
g_variant_unref (out);
|
2017-08-03 17:12:50 +02:00
|
|
|
g_object_unref (fds);
|
2021-07-08 19:25:21 +02:00
|
|
|
return -1;
|
2017-02-17 13:56:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-07-08 19:25:21 +02:00
|
|
|
fd = g_unix_fd_list_get (fds, 0, NULL);
|
|
|
|
|
|
2017-02-17 13:56:21 +01:00
|
|
|
g_variant_unref (out);
|
2017-08-03 17:12:50 +02:00
|
|
|
g_object_unref (fds);
|
2017-02-17 13:56:21 +01:00
|
|
|
|
2021-07-08 19:25:21 +02:00
|
|
|
g_debug ("Acquired inhibitor lock (%i, %s)", fd, mode);
|
2017-02-17 13:56:21 +01:00
|
|
|
|
2021-07-08 19:25:21 +02:00
|
|
|
return fd;
|
2017-02-17 13:56:21 +01:00
|
|
|
}
|
|
|
|
|
|
2017-02-10 15:19:51 +01:00
|
|
|
/**
|
|
|
|
|
* up_backend_prepare_for_sleep:
|
|
|
|
|
*
|
|
|
|
|
* Callback for logind's PrepareForSleep signal. It receives
|
|
|
|
|
* a boolean that indicates if we are about to sleep (TRUE)
|
|
|
|
|
* or waking up (FALSE).
|
|
|
|
|
* In case of the waking up we refresh the devices so we are
|
|
|
|
|
* up to date, especially w.r.t. battery levels, since they
|
|
|
|
|
* might have changed drastically.
|
|
|
|
|
**/
|
|
|
|
|
static void
|
|
|
|
|
up_backend_prepare_for_sleep (GDBusConnection *connection,
|
|
|
|
|
const gchar *sender_name,
|
|
|
|
|
const gchar *object_path,
|
|
|
|
|
const gchar *interface_name,
|
|
|
|
|
const gchar *signal_name,
|
|
|
|
|
GVariant *parameters,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
UpBackend *backend = user_data;
|
|
|
|
|
gboolean will_sleep;
|
|
|
|
|
GPtrArray *array;
|
|
|
|
|
guint i;
|
|
|
|
|
|
|
|
|
|
if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(b)"))) {
|
|
|
|
|
g_warning ("logind PrepareForSleep has unexpected parameter(s)");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_variant_get (parameters, "(b)", &will_sleep);
|
|
|
|
|
|
|
|
|
|
if (will_sleep) {
|
|
|
|
|
up_daemon_pause_poll (backend->priv->daemon);
|
2022-02-25 10:08:19 +01:00
|
|
|
if (backend->priv->logind_delay_inhibitor_fd >= 0) {
|
2021-07-08 19:25:21 +02:00
|
|
|
close (backend->priv->logind_delay_inhibitor_fd);
|
2022-02-25 10:08:19 +01:00
|
|
|
backend->priv->logind_delay_inhibitor_fd = -1;
|
2021-07-08 19:25:21 +02:00
|
|
|
}
|
2017-02-10 15:19:51 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-08 19:25:21 +02:00
|
|
|
if (backend->priv->logind_delay_inhibitor_fd < 0)
|
|
|
|
|
backend->priv->logind_delay_inhibitor_fd = up_backend_inhibitor_lock_take (backend, "Pause device polling", "delay");
|
2017-02-17 13:56:21 +01:00
|
|
|
|
2017-02-10 15:19:51 +01:00
|
|
|
/* we are waking up, lets refresh all battery devices */
|
|
|
|
|
g_debug ("Woke up from sleep; about to refresh devices");
|
|
|
|
|
array = up_device_list_get_array (backend->priv->device_list);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < array->len; i++) {
|
|
|
|
|
UpDevice *device = UP_DEVICE (g_ptr_array_index (array, i));
|
|
|
|
|
up_device_refresh_internal (device);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_ptr_array_unref (array);
|
|
|
|
|
|
|
|
|
|
up_daemon_resume_poll (backend->priv->daemon);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-07-27 16:40:11 +01:00
|
|
|
static void
|
2010-01-18 12:32:06 +00:00
|
|
|
up_backend_class_init (UpBackendClass *klass)
|
2009-07-27 16:40:11 +01:00
|
|
|
{
|
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
2010-01-18 12:32:06 +00:00
|
|
|
object_class->finalize = up_backend_finalize;
|
2009-07-27 16:40:11 +01:00
|
|
|
|
|
|
|
|
signals [SIGNAL_DEVICE_ADDED] =
|
|
|
|
|
g_signal_new ("device-added",
|
|
|
|
|
G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
|
2010-01-18 12:32:06 +00:00
|
|
|
G_STRUCT_OFFSET (UpBackendClass, device_added),
|
2015-06-01 10:26:41 -07:00
|
|
|
NULL, NULL, NULL,
|
2009-09-11 12:05:16 +01:00
|
|
|
G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
|
2009-07-27 16:40:11 +01:00
|
|
|
signals [SIGNAL_DEVICE_REMOVED] =
|
|
|
|
|
g_signal_new ("device-removed",
|
|
|
|
|
G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
|
2010-01-18 12:32:06 +00:00
|
|
|
G_STRUCT_OFFSET (UpBackendClass, device_removed),
|
2015-06-01 10:26:41 -07:00
|
|
|
NULL, NULL, NULL,
|
2009-07-27 16:40:11 +01:00
|
|
|
G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2010-01-18 12:32:06 +00:00
|
|
|
up_backend_init (UpBackend *backend)
|
2009-07-27 16:40:11 +01:00
|
|
|
{
|
2017-02-10 15:19:51 +01:00
|
|
|
GDBusConnection *bus;
|
|
|
|
|
guint sleep_id;
|
|
|
|
|
|
2019-02-21 12:09:06 +01:00
|
|
|
backend->priv = up_backend_get_instance_private (backend);
|
2011-03-14 11:01:12 +00:00
|
|
|
backend->priv->config = up_config_new ();
|
2010-01-18 12:49:30 +00:00
|
|
|
backend->priv->managed_devices = up_device_list_new ();
|
2013-10-13 02:46:32 +02:00
|
|
|
backend->priv->logind_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
|
|
|
|
|
0,
|
|
|
|
|
NULL,
|
|
|
|
|
LOGIND_DBUS_NAME,
|
|
|
|
|
LOGIND_DBUS_PATH,
|
|
|
|
|
LOGIND_DBUS_INTERFACE,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL);
|
2017-02-10 15:19:51 +01:00
|
|
|
|
|
|
|
|
bus = g_dbus_proxy_get_connection (backend->priv->logind_proxy);
|
|
|
|
|
sleep_id = g_dbus_connection_signal_subscribe (bus,
|
|
|
|
|
LOGIND_DBUS_NAME,
|
|
|
|
|
LOGIND_DBUS_INTERFACE,
|
|
|
|
|
"PrepareForSleep",
|
|
|
|
|
LOGIND_DBUS_PATH,
|
|
|
|
|
NULL,
|
|
|
|
|
G_DBUS_SIGNAL_FLAGS_NONE,
|
|
|
|
|
up_backend_prepare_for_sleep,
|
|
|
|
|
backend,
|
|
|
|
|
NULL);
|
|
|
|
|
backend->priv->logind_sleep_id = sleep_id;
|
2021-07-08 19:25:21 +02:00
|
|
|
backend->priv->logind_delay_inhibitor_fd = -1;
|
2017-02-17 13:56:21 +01:00
|
|
|
|
2021-07-08 19:25:21 +02:00
|
|
|
backend->priv->logind_delay_inhibitor_fd = up_backend_inhibitor_lock_take (backend, "Pause device polling", "delay");
|
2009-07-27 16:40:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2010-01-18 12:32:06 +00:00
|
|
|
up_backend_finalize (GObject *object)
|
2009-07-27 16:40:11 +01:00
|
|
|
{
|
2010-01-18 12:32:06 +00:00
|
|
|
UpBackend *backend;
|
2017-02-10 15:19:51 +01:00
|
|
|
GDBusConnection *bus;
|
2009-07-27 16:40:11 +01:00
|
|
|
|
2010-01-18 12:32:06 +00:00
|
|
|
g_return_if_fail (UP_IS_BACKEND (object));
|
2009-07-27 16:40:11 +01:00
|
|
|
|
2010-01-18 12:32:06 +00:00
|
|
|
backend = UP_BACKEND (object);
|
2009-07-27 16:40:11 +01:00
|
|
|
|
2017-10-20 17:15:53 +02:00
|
|
|
if (backend->priv->bluez_watch_id > 0) {
|
|
|
|
|
g_bus_unwatch_name (backend->priv->bluez_watch_id);
|
|
|
|
|
backend->priv->bluez_watch_id = 0;
|
|
|
|
|
}
|
|
|
|
|
g_clear_object (&backend->priv->bluez_client);
|
|
|
|
|
|
2017-10-19 19:14:59 +02:00
|
|
|
g_clear_object (&backend->priv->config);
|
|
|
|
|
g_clear_object (&backend->priv->daemon);
|
|
|
|
|
g_clear_object (&backend->priv->device_list);
|
|
|
|
|
g_clear_object (&backend->priv->gudev_client);
|
2017-02-10 15:19:51 +01:00
|
|
|
|
|
|
|
|
bus = g_dbus_proxy_get_connection (backend->priv->logind_proxy);
|
|
|
|
|
g_dbus_connection_signal_unsubscribe (bus,
|
|
|
|
|
backend->priv->logind_sleep_id);
|
|
|
|
|
|
2021-07-08 19:25:21 +02:00
|
|
|
if (backend->priv->logind_delay_inhibitor_fd >= 0)
|
|
|
|
|
close (backend->priv->logind_delay_inhibitor_fd);
|
2017-02-17 13:56:21 +01:00
|
|
|
|
2013-10-13 02:46:32 +02:00
|
|
|
g_clear_object (&backend->priv->logind_proxy);
|
2009-07-27 16:40:11 +01:00
|
|
|
|
|
|
|
|
g_object_unref (backend->priv->managed_devices);
|
|
|
|
|
|
2010-01-18 12:32:06 +00:00
|
|
|
G_OBJECT_CLASS (up_backend_parent_class)->finalize (object);
|
2009-07-27 16:40:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2010-01-18 12:32:06 +00:00
|
|
|
* up_backend_new:
|
2009-07-27 16:40:11 +01:00
|
|
|
*
|
2010-01-18 12:32:06 +00:00
|
|
|
* Return value: a new %UpBackend object.
|
2009-07-27 16:40:11 +01:00
|
|
|
**/
|
2010-01-18 12:32:06 +00:00
|
|
|
UpBackend *
|
|
|
|
|
up_backend_new (void)
|
2009-07-27 16:40:11 +01:00
|
|
|
{
|
2013-10-11 09:31:25 +02:00
|
|
|
return g_object_new (UP_TYPE_BACKEND, NULL);
|
2009-07-27 16:40:11 +01:00
|
|
|
}
|
|
|
|
|
|