summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBastien Nocera <hadess@hadess.net>2010-05-28 01:56:35 +0100
committerRichard Hughes <richard@hughsie.com>2010-05-28 13:49:56 +0100
commit7019d214f82caf2ba83f7b34894a4d7920708831 (patch)
tree41d3ff54dd6794c7b99e0a68ab52ebc0b751c2a3 /src
parent0ece8dea46de101bbbce876cc5a1703b3293b11f (diff)
Add battery query support for iDevices
https://bugs.freedesktop.org/show_bug.cgi?id=28286 Signed-off-by: Richard Hughes <richard@hughsie.com>
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am3
-rw-r--r--src/linux/Makefile.am12
-rw-r--r--src/linux/up-backend.c12
-rw-r--r--src/linux/up-device-idevice.c284
-rw-r--r--src/linux/up-device-idevice.h57
5 files changed, 366 insertions, 2 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 967a3f1..7853172 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -109,7 +109,8 @@ if BACKEND_TYPE_LINUX
upowerd_LDADD += \
linux/libupshared.la \
$(USB_LIBS) \
- $(GUDEV_LIBS)
+ $(GUDEV_LIBS) \
+ $(IDEVICE_LIBS)
endif
upowerd_CFLAGS = \
diff --git a/src/linux/Makefile.am b/src/linux/Makefile.am
index 4d54ae3..fb36235 100644
--- a/src/linux/Makefile.am
+++ b/src/linux/Makefile.am
@@ -10,12 +10,19 @@ INCLUDES = \
$(DBUS_GLIB_CFLAGS) \
$(GUDEV_CFLAGS) \
$(POLKIT_CFLAGS) \
- $(GLIB_CFLAGS)
+ $(GLIB_CFLAGS) \
+ $(IDEVICE_CFLAGS)
if BACKEND_TYPE_LINUX
noinst_LTLIBRARIES = libupshared.la
endif
+if HAVE_IDEVICE
+idevice_files = up-device-idevice.c up-device-idevice.h
+else
+idevice_files =
+endif
+
libupshared_la_SOURCES = \
up-device-supply.c \
up-device-supply.h \
@@ -31,8 +38,11 @@ libupshared_la_SOURCES = \
up-native.c \
sysfs-utils.c \
sysfs-utils.h \
+ $(idevice_files) \
$(BUILT_SOURCES)
+EXTRA_DIST = up-device-idevice.c up-device-idevice.h
+
libupshared_la_CFLAGS = \
$(WARNINGFLAGS_C)
diff --git a/src/linux/up-backend.c b/src/linux/up-backend.c
index 574921d..2739c37 100644
--- a/src/linux/up-backend.c
+++ b/src/linux/up-backend.c
@@ -40,6 +40,9 @@
#include "up-device-wup.h"
#include "up-device-hid.h"
#include "up-input.h"
+#ifdef HAVE_IDEVICE
+#include "up-device-idevice.h"
+#endif /* HAVE_IDEVICE */
static void up_backend_class_init (UpBackendClass *klass);
static void up_backend_init (UpBackend *backend);
@@ -110,6 +113,15 @@ up_backend_device_new (UpBackend *backend, GUdevDevice *native)
} else if (g_strcmp0 (subsys, "usb") == 0) {
+#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 */
+
/* see if this is a CSR mouse or keyboard */
device = UP_DEVICE (up_device_csr_new ());
ret = up_device_coldplug (device, backend->priv->daemon, G_OBJECT (native));
diff --git a/src/linux/up-device-idevice.c b/src/linux/up-device-idevice.c
new file mode 100644
index 0000000..6e7a0c2
--- /dev/null
+++ b/src/linux/up-device-idevice.c
@@ -0,0 +1,284 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2010 Bastien Nocera <hadess@hadess.net>
+ * Copyright (C) 2005-2010 Richard Hughes <richard@hughsie.com>
+ * Copyright (C) 2004 Sergey V. Udaltsov <svu@gnome.org>
+ *
+ * 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
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+#include <math.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <glib/gprintf.h>
+#include <glib/gi18n-lib.h>
+#include <glib-object.h>
+#include <gudev/gudev.h>
+#include <libimobiledevice/libimobiledevice.h>
+#include <libimobiledevice/lockdown.h>
+#include <plist/plist.h>
+
+#include "sysfs-utils.h"
+#include "egg-debug.h"
+
+#include "up-types.h"
+#include "up-device-idevice.h"
+
+#define UP_DEVICE_IDEVICE_DEFAULT_POLL_TIME 60 /* seconds */
+
+struct UpDeviceIdevicePrivate
+{
+ idevice_t dev;
+ lockdownd_client_t client;
+ guint poll_timer_id;
+};
+
+G_DEFINE_TYPE (UpDeviceIdevice, up_device_idevice, UP_TYPE_DEVICE)
+#define UP_DEVICE_IDEVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), UP_TYPE_DEVICE_IDEVICE, UpDeviceIdevicePrivate))
+
+static gboolean up_device_idevice_refresh (UpDevice *device);
+
+/**
+ * up_device_idevice_poll_cb:
+ **/
+static gboolean
+up_device_idevice_poll_cb (UpDeviceIdevice *idevice)
+{
+ UpDevice *device = UP_DEVICE (idevice);
+
+ egg_debug ("Polling: %s", up_device_get_object_path (device));
+ up_device_idevice_refresh (device);
+
+ /* always continue polling */
+ return TRUE;
+}
+
+/**
+ * up_device_idevice_coldplug:
+ *
+ * Return %TRUE on success, %FALSE if we failed to get data and should be removed
+ **/
+static gboolean
+up_device_idevice_coldplug (UpDevice *device)
+{
+ UpDeviceIdevice *idevice = UP_DEVICE_IDEVICE (device);
+ GUdevDevice *native;
+ gboolean ret = FALSE;
+ idevice_error_t retval;
+ const gchar *uuid;
+ const gchar *model;
+ plist_t dict = NULL;
+ plist_t node;
+ guint64 poll_seconds = 0;
+ idevice_t dev = NULL;
+ lockdownd_client_t client = NULL;
+ UpDeviceKind kind;
+
+ /* Is it an iDevice? */
+ native = G_UDEV_DEVICE (up_device_get_native (device));
+ if (g_udev_device_get_property_as_boolean (native, "USBMUX_SUPPORTED") == FALSE)
+ goto out;
+
+ /* Get the UUID */
+ uuid = g_udev_device_get_property (native, "ID_SERIAL_SHORT");
+ if (uuid == NULL)
+ goto out;
+
+ /* Connect to the device */
+ retval = idevice_new (&dev, uuid);
+ if (retval != IDEVICE_E_SUCCESS)
+ goto out;
+ if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake (dev, &client, "upower"))
+ goto out;
+
+ /* Get the poll timeout */
+ if (lockdownd_get_value (client, "com.apple.mobile.iTunes", "BatteryPollInterval", &dict) != LOCKDOWN_E_SUCCESS)
+ goto out;
+ node = plist_dict_get_item (dict, "BatteryPollInterval");
+ if (node != NULL)
+ plist_get_uint_val (node, &poll_seconds);
+ if (poll_seconds == 0)
+ poll_seconds = UP_DEVICE_IDEVICE_DEFAULT_POLL_TIME;
+
+ /* Set up struct */
+ idevice->priv->dev = dev;
+ idevice->priv->client = client;
+
+ /* find the kind of device */
+ model = g_udev_device_get_property (native, "ID_MODEL");
+ kind = UP_DEVICE_KIND_PHONE;
+ if (model != NULL && g_strstr_len (model, -1, "iPad")) {
+ kind = UP_DEVICE_KIND_TABLET;
+ } else if (model != NULL && g_strstr_len (model, -1, "iPod")) {
+ kind = UP_DEVICE_KIND_MEDIA_PLAYER;
+ }
+
+ /* hardcode some values */
+ //FIXME can we use the device name here?
+ g_object_set (device,
+ "type", kind,
+ "serial", uuid,
+ "vendor", g_udev_device_get_property (native, "ID_VENDOR"),
+ "model", g_udev_device_get_property (native, "ID_MODEL"),
+ "power-supply", FALSE,
+ "is-present", TRUE,
+ "is-rechargeable", TRUE,
+ "has-history", TRUE,
+ NULL);
+
+ /* coldplug */
+ ret = up_device_idevice_refresh (device);
+
+ /* disconnect */
+ lockdownd_client_free (idevice->priv->client);
+ idevice->priv->client = NULL;
+
+ /* set up a poll */
+ idevice->priv->poll_timer_id = g_timeout_add_seconds (poll_seconds,
+ (GSourceFunc) up_device_idevice_poll_cb, idevice);
+out:
+ if (dict != NULL)
+ plist_free (dict);
+ if (client != NULL)
+ lockdownd_client_free (client);
+ return ret;
+}
+
+/**
+ * up_device_idevice_refresh:
+ *
+ * Return %TRUE on success, %FALSE if we failed to refresh or no data
+ **/
+static gboolean
+up_device_idevice_refresh (UpDevice *device)
+{
+ GTimeVal timeval;
+ UpDeviceIdevice *idevice = UP_DEVICE_IDEVICE (device);
+ lockdownd_client_t client = NULL;
+ plist_t dict, node;
+ guint64 percentage;
+ guint8 charging;
+ UpDeviceState state;
+
+ /* Open a lockdown port, or re-use the one we have */
+ if (idevice->priv->client == NULL) {
+ if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake (idevice->priv->dev, &client, "upower"))
+ return FALSE;
+ } else {
+ client = idevice->priv->client;
+ }
+
+ /* get values */
+ if (lockdownd_get_value (idevice->priv->client, "com.apple.mobile.battery", NULL, &dict) != LOCKDOWN_E_SUCCESS)
+ return FALSE;
+
+ /* get battery status */
+ node = plist_dict_get_item (dict, "BatteryCurrentCapacity");
+ plist_get_uint_val (node, &percentage);
+
+ g_object_set (device, "percentage", (double) percentage, NULL);
+ egg_debug ("percentage=%"G_GUINT64_FORMAT, percentage);
+
+ /* get charging status */
+ node = plist_dict_get_item (dict, "BatteryIsCharging");
+ plist_get_bool_val (node, &charging);
+
+ if (percentage == 100)
+ state = UP_DEVICE_STATE_FULLY_CHARGED;
+ else if (percentage == 0)
+ state = UP_DEVICE_STATE_EMPTY;
+ else if (charging)
+ state = UP_DEVICE_STATE_CHARGING;
+ else
+ state = UP_DEVICE_STATE_DISCHARGING; /* upower doesn't have a "not charging" state */
+
+ g_object_set (device,
+ "state", state,
+ NULL);
+ egg_debug ("state=%s", up_device_state_to_string (state));
+
+ plist_free (dict);
+
+ /* reset time */
+ g_get_current_time (&timeval);
+ g_object_set (device, "update-time", (guint64) timeval.tv_sec, NULL);
+
+ return TRUE;
+}
+
+/**
+ * up_device_idevice_init:
+ **/
+static void
+up_device_idevice_init (UpDeviceIdevice *idevice)
+{
+ idevice->priv = UP_DEVICE_IDEVICE_GET_PRIVATE (idevice);
+}
+
+/**
+ * up_device_idevice_finalize:
+ **/
+static void
+up_device_idevice_finalize (GObject *object)
+{
+ UpDeviceIdevice *idevice;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (UP_IS_DEVICE_IDEVICE (object));
+
+ idevice = UP_DEVICE_IDEVICE (object);
+ g_return_if_fail (idevice->priv != NULL);
+
+ if (idevice->priv->poll_timer_id > 0)
+ g_source_remove (idevice->priv->poll_timer_id);
+ if (idevice->priv->client != NULL)
+ lockdownd_client_free (idevice->priv->client);
+ idevice_free (idevice->priv->dev);
+
+ G_OBJECT_CLASS (up_device_idevice_parent_class)->finalize (object);
+}
+
+/**
+ * up_device_idevice_class_init:
+ **/
+static void
+up_device_idevice_class_init (UpDeviceIdeviceClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ UpDeviceClass *device_class = UP_DEVICE_CLASS (klass);
+
+ object_class->finalize = up_device_idevice_finalize;
+ device_class->coldplug = up_device_idevice_coldplug;
+ device_class->refresh = up_device_idevice_refresh;
+
+ g_type_class_add_private (klass, sizeof (UpDeviceIdevicePrivate));
+}
+
+/**
+ * up_device_idevice_new:
+ **/
+UpDeviceIdevice *
+up_device_idevice_new (void)
+{
+ return g_object_new (UP_TYPE_DEVICE_IDEVICE, NULL);
+}
+
diff --git a/src/linux/up-device-idevice.h b/src/linux/up-device-idevice.h
new file mode 100644
index 0000000..4f37ab5
--- /dev/null
+++ b/src/linux/up-device-idevice.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2010 Bastien Nocera <hadess@hadess.net>
+ * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
+ * Copyright (C) 2008 Richard Hughes <richard@hughsie.com>
+ *
+ * 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
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __UP_DEVICE_IDEVICE_H__
+#define __UP_DEVICE_IDEVICE_H__
+
+#include <glib-object.h>
+#include "up-device.h"
+
+G_BEGIN_DECLS
+
+#define UP_TYPE_DEVICE_IDEVICE (up_device_idevice_get_type ())
+#define UP_DEVICE_IDEVICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), UP_TYPE_DEVICE_IDEVICE, UpDeviceIdevice))
+#define UP_DEVICE_IDEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), UP_TYPE_DEVICE_IDEVICE, UpDeviceIdeviceClass))
+#define UP_IS_DEVICE_IDEVICE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), UP_TYPE_DEVICE_IDEVICE))
+#define UP_IS_DEVICE_IDEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), UP_TYPE_DEVICE_IDEVICE))
+#define UP_DEVICE_IDEVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), UP_TYPE_DEVICE_IDEVICE, UpDeviceIdeviceClass))
+
+typedef struct UpDeviceIdevicePrivate UpDeviceIdevicePrivate;
+
+typedef struct
+{
+ UpDevice parent;
+ UpDeviceIdevicePrivate *priv;
+} UpDeviceIdevice;
+
+typedef struct
+{
+ UpDeviceClass parent_class;
+} UpDeviceIdeviceClass;
+
+GType up_device_idevice_get_type (void);
+UpDeviceIdevice *up_device_idevice_new (void);
+
+G_END_DECLS
+
+#endif /* __UP_DEVICE_IDEVICE_H__ */
+