Commit b1f12feb authored by Richard Hughes's avatar Richard Hughes

Factor out the Logitech Unifying support to support other devices

parent b188a49a
......@@ -20,3 +20,8 @@ ATTR{idVendor}=="046d", ATTR{idProduct}=="c702", ENV{UPOWER_PRODUCT}="Presenter"
LABEL="up_csr_end"
# Unifying HID++ devices
SUBSYSTEM!="hid", GOTO="up_unifying_end"
ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c52b", DRIVER=="logitech-djdevice", ENV{UPOWER_BATTERY_TYPE}="unifying"
ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c532", DRIVER=="logitech-djdevice", ENV{UPOWER_BATTERY_TYPE}="unifying"
LABEL="up_unifying_end"
......@@ -30,8 +30,8 @@ libupshared_la_SOURCES = \
up-device-supply.h \
up-device-csr.c \
up-device-csr.h \
up-device-lg-unifying.c \
up-device-lg-unifying.h \
up-device-unifying.c \
up-device-unifying.h \
up-device-hid.c \
up-device-hid.h \
up-device-wup.c \
......@@ -42,11 +42,25 @@ libupshared_la_SOURCES = \
up-dock.h \
up-backend.c \
up-native.c \
hidpp-device.c \
hidpp-device.h \
sysfs-utils.c \
sysfs-utils.h \
$(idevice_files) \
$(BUILT_SOURCES)
noinst_PROGRAMS = \
hidpp-test
hidpp_test_SOURCES = \
hidpp-device.c \
hidpp-device.h \
hidpp-test.c
hidpp_test_LDADD = \
-lm \
$(GLIB_LIBS) \
$(GIO_LIBS)
hidpp_test_CFLAGS = $(AM_CFLAGS) $(WARNINGFLAGS_C)
EXTRA_DIST = $(libupshared_la_SOURCES) \
integration-test
......
This diff is collapsed.
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2012 Julien Danjou <julien@danjou.info>
* Copyright (C) 2012 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 __HIDPP_DEVICE_H__
#define __HIDPP_DEVICE_H__
#include <glib-object.h>
#include "hidpp-device.h"
G_BEGIN_DECLS
#define HIDPP_TYPE_DEVICE (hidpp_device_get_type ())
#define HIDPP_DEVICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), HIDPP_TYPE_DEVICE, HidppDevice))
#define HIDPP_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), HIDPP_TYPE_DEVICE, HidppDeviceClass))
#define HIDPP_IS_DEVICE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), HIDPP_TYPE_DEVICE))
#define HIDPP_IS_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), HIDPP_TYPE_DEVICE))
#define HIDPP_DEVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), HIDPP_TYPE_DEVICE, HidppDeviceClass))
typedef struct HidppDevicePrivate HidppDevicePrivate;
typedef struct
{
GObject parent;
HidppDevicePrivate *priv;
} HidppDevice;
typedef struct
{
GObjectClass parent_class;
} HidppDeviceClass;
typedef enum {
HIDPP_DEVICE_KIND_KEYBOARD,
HIDPP_DEVICE_KIND_MOUSE,
HIDPP_DEVICE_KIND_TOUCHPAD,
HIDPP_DEVICE_KIND_TRACKBALL,
HIDPP_DEVICE_KIND_TABLET,
HIDPP_DEVICE_KIND_UNKNOWN
} HidppDeviceKind;
typedef enum {
HIDPP_DEVICE_BATT_STATUS_CHARGING,
HIDPP_DEVICE_BATT_STATUS_DISCHARGING,
HIDPP_DEVICE_BATT_STATUS_CHARGED,
HIDPP_DEVICE_BATT_STATUS_UNKNOWN
} HidppDeviceBattStatus;
typedef enum {
HIDPP_REFRESH_FLAGS_VERSION = 1,
HIDPP_REFRESH_FLAGS_KIND = 2,
HIDPP_REFRESH_FLAGS_BATTERY = 4,
HIDPP_REFRESH_FLAGS_MODEL = 8
} HidppRefreshFlags;
GType hidpp_device_get_type (void);
const gchar *hidpp_device_get_model (HidppDevice *device);
guint hidpp_device_get_batt_percentage (HidppDevice *device);
guint hidpp_device_get_version (HidppDevice *device);
HidppDeviceBattStatus hidpp_device_get_batt_status (HidppDevice *device);
HidppDeviceKind hidpp_device_get_kind (HidppDevice *device);
void hidpp_device_set_hidraw_device (HidppDevice *device,
const gchar *hidraw_device);
void hidpp_device_set_index (HidppDevice *device,
guint device_idx);
void hidpp_device_set_enable_debug (HidppDevice *device,
gboolean enable_debug);
gboolean hidpp_device_refresh (HidppDevice *device,
HidppRefreshFlags refresh_flags,
GError **error);
HidppDevice *hidpp_device_new (void);
G_END_DECLS
#endif /* __HIDPP_DEVICE_H__ */
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2012 Richard Hughes <richard@hughsie.com>
*
* 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
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include <glib.h>
#include <glib-object.h>
#include "hidpp-device.h"
int
main (int argc, char **argv)
{
// const gchar *model;
// guint batt_percentage;
// guint version;
// HidppDeviceBattStatus batt_status;
HidppDevice *d;
// HidppDeviceKind kind;
gboolean ret;
GError *error = NULL;
g_type_init ();
g_test_init (&argc, &argv, NULL);
d = hidpp_device_new ();
hidpp_device_set_enable_debug (d, TRUE);
g_assert_cmpint (hidpp_device_get_version (d), ==, 0);
g_assert_cmpstr (hidpp_device_get_model (d), ==, NULL);
g_assert_cmpint (hidpp_device_get_batt_percentage (d), ==, 0);
g_assert_cmpint (hidpp_device_get_batt_status (d), ==, HIDPP_DEVICE_BATT_STATUS_UNKNOWN);
g_assert_cmpint (hidpp_device_get_kind (d), ==, HIDPP_DEVICE_KIND_UNKNOWN);
/* setup */
hidpp_device_set_hidraw_device (d, "/dev/hidraw0");
hidpp_device_set_index (d, 1);
ret = hidpp_device_refresh (d,
HIDPP_REFRESH_FLAGS_VERSION |
HIDPP_REFRESH_FLAGS_KIND |
HIDPP_REFRESH_FLAGS_BATTERY |
HIDPP_REFRESH_FLAGS_MODEL,
&error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpint (hidpp_device_get_version (d), !=, 0);
g_assert_cmpstr (hidpp_device_get_model (d), !=, NULL);
g_assert_cmpint (hidpp_device_get_batt_percentage (d), !=, 0);
g_assert_cmpint (hidpp_device_get_batt_status (d), !=, HIDPP_DEVICE_BATT_STATUS_UNKNOWN);
g_assert_cmpint (hidpp_device_get_kind (d), !=, HIDPP_DEVICE_KIND_UNKNOWN);
g_print ("Version:\t\t%i\n", hidpp_device_get_version (d));
g_print ("Kind:\t\t\t%i\n", hidpp_device_get_kind (d));
g_print ("Model:\t\t\t%s\n", hidpp_device_get_model (d));
g_print ("Battery Percentage:\t%i\n", hidpp_device_get_batt_percentage (d));
g_print ("Battery Status:\t\t%i\n", hidpp_device_get_batt_status (d));
g_object_unref (d);
return 0;
}
......@@ -36,7 +36,7 @@
#include "up-device-supply.h"
#include "up-device-csr.h"
#include "up-device-lg-unifying.h"
#include "up-device-unifying.h"
#include "up-device-wup.h"
#include "up-device-hid.h"
#include "up-input.h"
......@@ -118,6 +118,18 @@ up_backend_device_new (UpBackend *backend, GUdevDevice *native)
/* no valid power supply object */
device = NULL;
} 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;
g_object_unref (device);
/* no valid power supply object */
device = NULL;
} else if (g_strcmp0 (subsys, "tty") == 0) {
/* try to detect a Watts Up? Pro monitor */
......@@ -176,18 +188,8 @@ up_backend_device_new (UpBackend *backend, GUdevDevice *native)
/* no valid input object */
device = NULL;
} else {
g_object_unref (input);
/* 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) {
g_object_unref (device);
/* no valid input object */
device = NULL;
}
}
g_object_unref (input);
} else {
native_path = g_udev_device_get_sysfs_path (native);
g_warning ("native path %s (%s) ignoring", native_path, subsys);
......@@ -328,7 +330,7 @@ up_backend_coldplug (UpBackend *backend, UpDaemon *daemon)
GList *l;
guint i;
gboolean ret;
const gchar *subsystems[] = {"power_supply", "usb", "usbmisc", "tty", "input", NULL};
const gchar *subsystems[] = {"power_supply", "usb", "usbmisc", "tty", "input", "hid", NULL};
backend->priv->daemon = g_object_ref (daemon);
backend->priv->device_list = up_daemon_get_device_list (daemon);
......
This diff is collapsed.
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2012 Julien Danjou <julien@danjou.info>
*
* 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 <glib-object.h>
#include <gudev/gudev.h>
#include "hidpp-device.h"
#include "up-device-unifying.h"
#include "up-types.h"
#define UP_DEVICE_UNIFYING_REFRESH_TIMEOUT 60 /* seconds */
struct UpDeviceUnifyingPrivate
{
guint poll_timer_id;
HidppDevice *hidpp_device;
};
G_DEFINE_TYPE (UpDeviceUnifying, up_device_unifying, UP_TYPE_DEVICE)
#define UP_DEVICE_UNIFYING_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), UP_TYPE_DEVICE_UNIFYING, UpDeviceUnifyingPrivate))
/**
* up_device_unifying_refresh:
*
* Return %TRUE on success, %FALSE if we failed to refresh or no data
**/
static gboolean
up_device_unifying_refresh (UpDevice *device)
{
gboolean ret;
GError *error = NULL;
GTimeVal timeval;
UpDeviceState state = UP_DEVICE_STATE_UNKNOWN;
UpDeviceUnifying *unifying = UP_DEVICE_UNIFYING (device);
UpDeviceUnifyingPrivate *priv = unifying->priv;
/* refresh just the battery stats */
ret = hidpp_device_refresh (priv->hidpp_device,
HIDPP_REFRESH_FLAGS_BATTERY,
&error);
if (!ret) {
g_warning ("failed to coldplug unifying device: %s",
error->message);
g_error_free (error);
goto out;
}
switch (hidpp_device_get_batt_status (priv->hidpp_device)) {
case HIDPP_DEVICE_BATT_STATUS_CHARGING:
state = UP_DEVICE_STATE_CHARGING;
break;
case HIDPP_DEVICE_BATT_STATUS_DISCHARGING:
state = UP_DEVICE_STATE_DISCHARGING;
break;
case HIDPP_DEVICE_BATT_STATUS_CHARGED:
state = UP_DEVICE_STATE_FULLY_CHARGED;
break;
default:
break;
}
g_get_current_time (&timeval);
g_object_set (device,
"is-present", hidpp_device_get_version (priv->hidpp_device) > 0,
"percentage", (gdouble) hidpp_device_get_batt_percentage (priv->hidpp_device),
"state", state,
"update-time", (guint64) timeval.tv_sec,
NULL);
out:
return TRUE;
}
static UpDeviceKind
up_device_unifying_get_device_kind (UpDeviceUnifying *unifying)
{
UpDeviceKind kind;
switch (hidpp_device_get_kind (unifying->priv->hidpp_device)) {
case HIDPP_DEVICE_KIND_MOUSE:
case HIDPP_DEVICE_KIND_TOUCHPAD:
case HIDPP_DEVICE_KIND_TRACKBALL:
kind = UP_DEVICE_KIND_MOUSE;
break;
case HIDPP_DEVICE_KIND_KEYBOARD:
kind = UP_DEVICE_KIND_KEYBOARD;
break;
case HIDPP_DEVICE_KIND_TABLET:
kind = UP_DEVICE_KIND_TABLET;
break;
default:
kind = UP_DEVICE_KIND_UNKNOWN;
}
return kind;
}
/**
* up_device_unifying_coldplug:
*
* Return %TRUE on success, %FALSE if we failed to get data and should be removed
**/
static gboolean
up_device_unifying_coldplug (UpDevice *device)
{
const gchar *bus_address;
const gchar *device_file;
const gchar *type;
gboolean ret = FALSE;
gchar *endptr = NULL;
gchar *tmp;
GError *error = NULL;
GUdevDevice *native;
GUdevDevice *parent = NULL;
GUdevDevice *receiver = NULL;
UpDeviceUnifying *unifying = UP_DEVICE_UNIFYING (device);
GUdevClient *client = NULL;
GList *hidraw_list = NULL;
GList *l;
native = G_UDEV_DEVICE (up_device_get_native (device));
/* check if we have the right device */
type = g_udev_device_get_property (native, "UPOWER_BATTERY_TYPE");
if (type == NULL)
goto out;
if (g_strcmp0 (type, "unifying") != 0)
goto out;
/* get the device index */
unifying->priv->hidpp_device = hidpp_device_new ();
bus_address = g_udev_device_get_property (native, "HID_PHYS");
tmp = g_strrstr (bus_address, ":");
if (tmp == NULL) {
g_debug ("Could not get physical device index");
goto out;
}
hidpp_device_set_index (unifying->priv->hidpp_device,
g_ascii_strtoull (tmp + 1, &endptr, 10));
if (endptr != NULL && endptr[0] != '\0') {
g_debug ("HID_PHYS malformed: '%s'", bus_address);
goto out;
}
/* find the hidraw device that matches the parent */
parent = g_udev_device_get_parent (native);
client = g_udev_client_new (NULL);
hidraw_list = g_udev_client_query_by_subsystem (client, "hidraw");
for (l = hidraw_list; l != NULL; l = l->next) {
if (g_strcmp0 (g_udev_device_get_sysfs_path (parent),
g_udev_device_get_sysfs_attr (l->data, "device")) == 0) {
receiver = g_object_ref (l->data);
break;
}
}
if (receiver == NULL) {
g_debug ("Unable to find an hidraw device for Unifying receiver");
return FALSE;
}
/* connect to the receiver */
device_file = g_udev_device_get_device_file (receiver);
if (device_file == NULL) {
g_debug ("Could not get device file for Unifying receiver device");
goto out;
}
g_debug ("Using Unifying receiver hidraw device file: %s", device_file);
hidpp_device_set_hidraw_device (unifying->priv->hidpp_device,
device_file);
/* coldplug initial parameters */
ret = hidpp_device_refresh (unifying->priv->hidpp_device,
HIDPP_REFRESH_FLAGS_VERSION |
HIDPP_REFRESH_FLAGS_KIND |
HIDPP_REFRESH_FLAGS_MODEL,
&error);
if (!ret) {
g_warning ("failed to coldplug unifying device: %s",
error->message);
g_error_free (error);
goto out;
}
/* set some default values */
g_object_set (device,
"vendor", g_udev_device_get_property (native, "ID_VENDOR"),
"type", up_device_unifying_get_device_kind (unifying),
"model", hidpp_device_get_model (unifying->priv->hidpp_device),
"has-history", TRUE,
"is-rechargeable", TRUE,
"power-supply", FALSE,
NULL);
/* set up a poll to send the magic packet */
up_device_unifying_refresh (device);
unifying->priv->poll_timer_id = g_timeout_add_seconds (UP_DEVICE_UNIFYING_REFRESH_TIMEOUT,
(GSourceFunc) up_device_unifying_refresh,
device);
ret = TRUE;
out:
g_list_foreach (hidraw_list, (GFunc) g_object_unref, NULL);
g_list_free (hidraw_list);
if (parent != NULL)
g_object_unref (parent);
if (receiver != NULL)
g_object_unref (receiver);
if (client != NULL)
g_object_unref (client);
return ret;
}
/**
* up_device_unifying_init:
**/
static void
up_device_unifying_init (UpDeviceUnifying *unifying)
{
unifying->priv = UP_DEVICE_UNIFYING_GET_PRIVATE (unifying);
unifying->priv->poll_timer_id = 0;
}
/**
* up_device_unifying_finalize:
**/
static void
up_device_unifying_finalize (GObject *object)
{
UpDeviceUnifying *unifying;
g_return_if_fail (object != NULL);
g_return_if_fail (UP_IS_DEVICE_UNIFYING (object));
unifying = UP_DEVICE_UNIFYING (object);
g_return_if_fail (unifying->priv != NULL);
if (unifying->priv->poll_timer_id > 0)
g_source_remove (unifying->priv->poll_timer_id);
if (unifying->priv->hidpp_device != NULL)
g_object_unref (unifying->priv->hidpp_device);
G_OBJECT_CLASS (up_device_unifying_parent_class)->finalize (object);
}
/**
* up_device_unifying_class_init:
**/
static void
up_device_unifying_class_init (UpDeviceUnifyingClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
UpDeviceClass *device_class = UP_DEVICE_CLASS (klass);
object_class->finalize = up_device_unifying_finalize;
device_class->coldplug = up_device_unifying_coldplug;
device_class->refresh = up_device_unifying_refresh;
g_type_class_add_private (klass, sizeof (UpDeviceUnifyingPrivate));
}
/**
* up_device_unifying_new:
**/
UpDeviceUnifying *
up_device_unifying_new (void)
{
return g_object_new (UP_TYPE_DEVICE_UNIFYING, NULL);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment