1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
3
* Copyright (C) 2012 Julien Danjou <julien@danjou.info>
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25
#include <glib-object.h>
26
#include <gudev/gudev.h>
28
#include "hidpp-device.h"
30
#include "up-device-unifying.h"
33
#define UP_DEVICE_UNIFYING_REFRESH_TIMEOUT 60 /* seconds */
35
struct UpDeviceUnifyingPrivate
38
HidppDevice *hidpp_device;
41
G_DEFINE_TYPE (UpDeviceUnifying, up_device_unifying, UP_TYPE_DEVICE)
42
#define UP_DEVICE_UNIFYING_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), UP_TYPE_DEVICE_UNIFYING, UpDeviceUnifyingPrivate))
45
* up_device_unifying_refresh:
47
* Return %TRUE on success, %FALSE if we failed to refresh or no data
50
up_device_unifying_refresh (UpDevice *device)
55
HidppRefreshFlags refresh_flags;
56
UpDeviceState state = UP_DEVICE_STATE_UNKNOWN;
57
UpDeviceUnifying *unifying = UP_DEVICE_UNIFYING (device);
58
UpDeviceUnifyingPrivate *priv = unifying->priv;
60
/* refresh the battery stats */
61
refresh_flags = HIDPP_REFRESH_FLAGS_BATTERY;
64
* Device hid++ v2 when in unreachable mode seems to be able
65
* to respond to hid++ v1 queries (but fails to respond to v2
66
* queries). When it gets waken up it starts responding
67
* to v2 queries, so always try to upgrade protocol to v2
69
if (hidpp_device_get_version (priv->hidpp_device) < 2)
70
refresh_flags |= HIDPP_REFRESH_FLAGS_VERSION;
72
ret = hidpp_device_refresh (priv->hidpp_device,
76
g_warning ("failed to coldplug unifying device: %s",
81
switch (hidpp_device_get_batt_status (priv->hidpp_device)) {
82
case HIDPP_DEVICE_BATT_STATUS_CHARGING:
83
state = UP_DEVICE_STATE_CHARGING;
85
case HIDPP_DEVICE_BATT_STATUS_DISCHARGING:
86
state = UP_DEVICE_STATE_DISCHARGING;
88
case HIDPP_DEVICE_BATT_STATUS_CHARGED:
89
state = UP_DEVICE_STATE_FULLY_CHARGED;
94
g_get_current_time (&timeval);
96
"is-present", hidpp_device_get_version (priv->hidpp_device) > 0,
97
"percentage", (gdouble) hidpp_device_get_batt_percentage (priv->hidpp_device),
99
"update-time", (guint64) timeval.tv_sec,
106
up_device_unifying_get_device_kind (UpDeviceUnifying *unifying)
109
switch (hidpp_device_get_kind (unifying->priv->hidpp_device)) {
110
case HIDPP_DEVICE_KIND_MOUSE:
111
case HIDPP_DEVICE_KIND_TOUCHPAD:
112
case HIDPP_DEVICE_KIND_TRACKBALL:
113
kind = UP_DEVICE_KIND_MOUSE;
115
case HIDPP_DEVICE_KIND_KEYBOARD:
116
kind = UP_DEVICE_KIND_KEYBOARD;
118
case HIDPP_DEVICE_KIND_TABLET:
119
kind = UP_DEVICE_KIND_TABLET;
122
kind = UP_DEVICE_KIND_UNKNOWN;
128
* up_device_unifying_coldplug:
130
* Return %TRUE on success, %FALSE if we failed to get data and should be removed
133
up_device_unifying_coldplug (UpDevice *device)
135
const gchar *bus_address;
136
const gchar *device_file;
139
gboolean ret = FALSE;
140
gchar *endptr = NULL;
142
GError *error = NULL;
144
GUdevDevice *parent = NULL;
145
GUdevDevice *receiver = NULL;
146
UpDeviceUnifying *unifying = UP_DEVICE_UNIFYING (device);
147
GUdevClient *client = NULL;
148
GList *hidraw_list = NULL;
151
native = G_UDEV_DEVICE (up_device_get_native (device));
153
/* check if we have the right device */
154
type = g_udev_device_get_property (native, "UPOWER_BATTERY_TYPE");
157
if ((g_strcmp0 (type, "unifying") != 0) && (g_strcmp0 (type, "lg-wireless") != 0))
160
/* get the device index */
161
unifying->priv->hidpp_device = hidpp_device_new ();
162
bus_address = g_udev_device_get_property (native, "HID_PHYS");
163
tmp = g_strrstr (bus_address, ":");
165
g_debug ("Could not get physical device index");
169
if (g_strcmp0 (type, "lg-wireless") == 0)
170
hidpp_device_set_index (unifying->priv->hidpp_device, 1);
172
hidpp_device_set_index (unifying->priv->hidpp_device,
173
g_ascii_strtoull (tmp + 1, &endptr, 10));
174
if (endptr != NULL && endptr[0] != '\0') {
175
g_debug ("HID_PHYS malformed: '%s'", bus_address);
180
/* find the hidraw device that matches */
181
parent = g_udev_device_get_parent (native);
182
client = g_udev_client_new (NULL);
183
hidraw_list = g_udev_client_query_by_subsystem (client, "hidraw");
184
for (l = hidraw_list; l != NULL; l = l->next) {
185
if (g_strcmp0 (type, "lg-wireless") == 0) {
186
gboolean receiver_found = FALSE;
187
const gchar *filename;
190
if (g_strcmp0 (g_udev_device_get_sysfs_path (native),
191
g_udev_device_get_sysfs_path(g_udev_device_get_parent(l->data))) != 0)
194
/* hidraw device which exposes hiddev interface is our receiver */
195
tmp = g_build_filename(g_udev_device_get_sysfs_path (g_udev_device_get_parent(native)),
197
dir = g_dir_open (tmp, 0, &error);
200
g_clear_error(&error);
203
while ( (filename = g_dir_read_name(dir)) ) {
204
if (g_ascii_strncasecmp(filename, "hiddev", 6) == 0) {
205
receiver_found = TRUE;
214
if (g_strcmp0 (g_udev_device_get_sysfs_path (parent),
215
g_udev_device_get_sysfs_path(g_udev_device_get_parent(l->data))) != 0)
218
receiver = g_object_ref (l->data);
221
if (receiver == NULL) {
222
g_debug ("Unable to find an hidraw device for Unifying receiver");
226
/* connect to the receiver */
227
device_file = g_udev_device_get_device_file (receiver);
228
if (device_file == NULL) {
229
g_debug ("Could not get device file for Unifying receiver device");
232
g_debug ("Using Unifying receiver hidraw device file: %s", device_file);
233
hidpp_device_set_hidraw_device (unifying->priv->hidpp_device,
236
/* coldplug initial parameters */
237
ret = hidpp_device_refresh (unifying->priv->hidpp_device,
238
HIDPP_REFRESH_FLAGS_VERSION |
239
HIDPP_REFRESH_FLAGS_KIND |
240
HIDPP_REFRESH_FLAGS_MODEL,
243
g_warning ("failed to coldplug unifying device: %s",
245
g_error_free (error);
249
vendor = g_udev_device_get_property (native, "UPOWER_VENDOR");
251
vendor = g_udev_device_get_property (native, "ID_VENDOR");
253
/* set some default values */
254
g_object_set (device,
256
"type", up_device_unifying_get_device_kind (unifying),
257
"model", hidpp_device_get_model (unifying->priv->hidpp_device),
259
"is-rechargeable", TRUE,
260
"power-supply", FALSE,
263
/* set up a poll to send the magic packet */
264
up_device_unifying_refresh (device);
265
unifying->priv->poll_timer_id = g_timeout_add_seconds (UP_DEVICE_UNIFYING_REFRESH_TIMEOUT,
266
(GSourceFunc) up_device_unifying_refresh,
270
g_list_foreach (hidraw_list, (GFunc) g_object_unref, NULL);
271
g_list_free (hidraw_list);
273
g_object_unref (parent);
274
if (receiver != NULL)
275
g_object_unref (receiver);
277
g_object_unref (client);
282
* up_device_unifying_init:
285
up_device_unifying_init (UpDeviceUnifying *unifying)
287
unifying->priv = UP_DEVICE_UNIFYING_GET_PRIVATE (unifying);
288
unifying->priv->poll_timer_id = 0;
292
* up_device_unifying_finalize:
295
up_device_unifying_finalize (GObject *object)
297
UpDeviceUnifying *unifying;
299
g_return_if_fail (object != NULL);
300
g_return_if_fail (UP_IS_DEVICE_UNIFYING (object));
302
unifying = UP_DEVICE_UNIFYING (object);
303
g_return_if_fail (unifying->priv != NULL);
305
if (unifying->priv->poll_timer_id > 0)
306
g_source_remove (unifying->priv->poll_timer_id);
307
if (unifying->priv->hidpp_device != NULL)
308
g_object_unref (unifying->priv->hidpp_device);
310
G_OBJECT_CLASS (up_device_unifying_parent_class)->finalize (object);
314
* up_device_unifying_class_init:
317
up_device_unifying_class_init (UpDeviceUnifyingClass *klass)
319
GObjectClass *object_class = G_OBJECT_CLASS (klass);
320
UpDeviceClass *device_class = UP_DEVICE_CLASS (klass);
322
object_class->finalize = up_device_unifying_finalize;
323
device_class->coldplug = up_device_unifying_coldplug;
324
device_class->refresh = up_device_unifying_refresh;
326
g_type_class_add_private (klass, sizeof (UpDeviceUnifyingPrivate));
330
* up_device_unifying_new:
333
up_device_unifying_new (void)
335
return g_object_new (UP_TYPE_DEVICE_UNIFYING, NULL);