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
|
|
|
|
2018-06-19 13:41:30 +02:00
|
|
|
#include "sysfs-utils.h"
|
|
|
|
|
|
2010-01-18 12:26:55 +00:00
|
|
|
#include "up-device-supply.h"
|
2013-01-09 10:28:58 +00:00
|
|
|
#include "up-device-unifying.h"
|
2010-01-18 12:26:55 +00:00
|
|
|
#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;
|
2017-02-17 13:56:21 +01:00
|
|
|
int logind_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
|
|
|
|
2010-01-18 12:32:06 +00:00
|
|
|
static gboolean up_backend_device_add (UpBackend *backend, GUdevDevice *native);
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
char *product;
|
|
|
|
|
gboolean ret = FALSE;
|
|
|
|
|
|
|
|
|
|
product = sysfs_get_string ("/sys/devices/virtual/dmi/id/", "product_name");
|
|
|
|
|
if (product == NULL)
|
|
|
|
|
return GINT_TO_POINTER(ret);
|
|
|
|
|
ret = g_str_has_prefix (product, "MacBook");
|
|
|
|
|
g_free (product);
|
|
|
|
|
return GINT_TO_POINTER(ret);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 ());
|
|
|
|
|
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
|
|
|
|
2013-01-09 10:28:58 +00:00
|
|
|
} else if (g_strcmp0 (subsys, "hid") == 0) {
|
|
|
|
|
|
|
|
|
|
/* see if this is a Unifying mouse or keyboard */
|
|
|
|
|
device = UP_DEVICE (up_device_unifying_new ());
|
|
|
|
|
ret = up_device_coldplug (device, backend->priv->daemon, G_OBJECT (native));
|
|
|
|
|
if (ret)
|
|
|
|
|
goto out;
|
|
|
|
|
/* no valid power supply object */
|
2017-10-19 19:14:59 +02:00
|
|
|
g_clear_object (&device);
|
2013-01-09 10:28:58 +00:00
|
|
|
|
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
|
2010-01-18 12:32:06 +00:00
|
|
|
up_backend_device_changed (UpBackend *backend, GUdevDevice *native)
|
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) {
|
2010-11-01 11:28:31 +00:00
|
|
|
g_warning ("treating change event as add on %s", g_udev_device_get_sysfs_path (native));
|
2010-01-18 12:32:06 +00:00
|
|
|
up_backend_device_add (backend, native);
|
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;
|
|
|
|
|
}
|
|
|
|
|
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
|
2010-01-18 12:32:06 +00:00
|
|
|
up_backend_device_add (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
|
|
|
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 */
|
2010-11-01 11:28:31 +00:00
|
|
|
g_warning ("treating add event as change event on %s", up_device_get_object_path (device));
|
2010-01-18 12:32:06 +00:00
|
|
|
up_backend_device_changed (backend, native);
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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));
|
2010-01-18 12:32:06 +00:00
|
|
|
up_backend_device_add (backend, device);
|
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));
|
2010-01-18 12:32:06 +00:00
|
|
|
up_backend_device_changed (backend, device);
|
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;
|
2013-10-12 14:55:30 +02:00
|
|
|
const gchar *subsystems_wup[] = {"power_supply", "usb", "usbmisc", "tty", "input", "hid", NULL};
|
|
|
|
|
const gchar *subsystems[] = {"power_supply", "usb", "usbmisc", "input", "hid", 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;
|
2010-01-18 12:32:06 +00:00
|
|
|
up_backend_device_add (backend, native);
|
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
|
|
|
|
|
*
|
|
|
|
|
* Acquire a sleep 'delay lock' via systemd's logind that will
|
|
|
|
|
* inhibit going to sleep until the lock is released again via
|
|
|
|
|
* up_backend_inhibitor_lock_release().
|
|
|
|
|
* Does nothing if the lock was already acquired.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
up_backend_inhibitor_lock_take (UpBackend *backend)
|
|
|
|
|
{
|
|
|
|
|
GVariant *out, *input;
|
2017-08-03 17:12:50 +02:00
|
|
|
GUnixFDList *fds = NULL;
|
2017-02-17 13:56:21 +01:00
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
|
|
if (backend->priv->logind_inhibitor_fd > -1) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
input = g_variant_new ("(ssss)",
|
|
|
|
|
"sleep", /* what */
|
|
|
|
|
"UPower", /* who */
|
|
|
|
|
"Pause device polling", /* why */
|
|
|
|
|
"delay"); /* mode */
|
|
|
|
|
|
|
|
|
|
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);
|
2017-02-17 13:56:21 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
2017-02-17 13:56:21 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
backend->priv->logind_inhibitor_fd = g_unix_fd_list_get (fds, 0, NULL);
|
|
|
|
|
g_variant_unref (out);
|
2017-08-03 17:12:50 +02:00
|
|
|
g_object_unref (fds);
|
2017-02-17 13:56:21 +01:00
|
|
|
|
|
|
|
|
g_debug ("Acquired inhibitor lock (%i)", backend->priv->logind_inhibitor_fd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* up_backend_inhibitor_lock_release:
|
|
|
|
|
* @backend: The %UpBackend class instance
|
|
|
|
|
*
|
|
|
|
|
* Releases a previously acquired inhibitor lock or does nothing
|
|
|
|
|
* if no lock is held;
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
up_backend_inhibitor_lock_release (UpBackend *backend)
|
|
|
|
|
{
|
|
|
|
|
if (backend->priv->logind_inhibitor_fd == -1) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
close (backend->priv->logind_inhibitor_fd);
|
|
|
|
|
backend->priv->logind_inhibitor_fd = -1;
|
|
|
|
|
|
|
|
|
|
g_debug ("Released inhibitor lock");
|
|
|
|
|
}
|
|
|
|
|
|
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);
|
2017-02-17 13:56:21 +01:00
|
|
|
up_backend_inhibitor_lock_release (backend);
|
2017-02-10 15:19:51 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-17 13:56:21 +01:00
|
|
|
up_backend_inhibitor_lock_take (backend);
|
|
|
|
|
|
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;
|
2017-02-17 13:56:21 +01:00
|
|
|
backend->priv->logind_inhibitor_fd = -1;
|
|
|
|
|
|
|
|
|
|
up_backend_inhibitor_lock_take (backend);
|
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);
|
|
|
|
|
|
2017-02-17 13:56:21 +01:00
|
|
|
up_backend_inhibitor_lock_release (backend);
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|