~ubuntu-branches/ubuntu/vivid/upower/vivid

« back to all changes in this revision

Viewing changes to .pc/00git_updates.patch/src/linux/up-device-unifying.c

  • Committer: Package Import Robot
  • Author(s): Martin Pitt
  • Date: 2013-09-06 15:19:05 UTC
  • Revision ID: package-import@ubuntu.com-20130906151905-rl005irvg7wd8p0h
Tags: 0.9.21-3ubuntu1
* Update 00git_updates.patch to today's upstream git:
  - Rework of hidpp detection to determine correct charge values for
    Logitech wireless keyboards/mouse (LP: #1103064)
  - Detect bluetooth mouse/keyboard batteries as such, instead of as system
    batteries. (LP: #115348)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
 
2
 *
 
3
 * Copyright (C) 2012 Julien Danjou <julien@danjou.info>
 
4
 *
 
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.
 
9
 *
 
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.
 
14
 *
 
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
 
18
 *
 
19
 */
 
20
 
 
21
#ifdef HAVE_CONFIG_H
 
22
#  include "config.h"
 
23
#endif
 
24
 
 
25
#include <glib-object.h>
 
26
#include <gudev/gudev.h>
 
27
 
 
28
#include "hidpp-device.h"
 
29
 
 
30
#include "up-device-unifying.h"
 
31
#include "up-types.h"
 
32
 
 
33
#define UP_DEVICE_UNIFYING_REFRESH_TIMEOUT                      60 /* seconds */
 
34
 
 
35
struct UpDeviceUnifyingPrivate
 
36
{
 
37
        guint                    poll_timer_id;
 
38
        HidppDevice             *hidpp_device;
 
39
};
 
40
 
 
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))
 
43
 
 
44
/**
 
45
 * up_device_unifying_refresh:
 
46
 *
 
47
 * Return %TRUE on success, %FALSE if we failed to refresh or no data
 
48
 **/
 
49
static gboolean
 
50
up_device_unifying_refresh (UpDevice *device)
 
51
{
 
52
        gboolean ret;
 
53
        GError *error = NULL;
 
54
        GTimeVal timeval;
 
55
        HidppRefreshFlags refresh_flags;
 
56
        UpDeviceState state = UP_DEVICE_STATE_UNKNOWN;
 
57
        UpDeviceUnifying *unifying = UP_DEVICE_UNIFYING (device);
 
58
        UpDeviceUnifyingPrivate *priv = unifying->priv;
 
59
 
 
60
        /* refresh the battery stats */
 
61
        refresh_flags = HIDPP_REFRESH_FLAGS_BATTERY;
 
62
 
 
63
        /*
 
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
 
68
         */
 
69
        if (hidpp_device_get_version (priv->hidpp_device) < 2)
 
70
                refresh_flags |= HIDPP_REFRESH_FLAGS_VERSION;
 
71
 
 
72
        ret = hidpp_device_refresh (priv->hidpp_device,
 
73
                                    refresh_flags,
 
74
                                    &error);
 
75
        if (!ret) {
 
76
                g_warning ("failed to coldplug unifying device: %s",
 
77
                           error->message);
 
78
                g_error_free (error);
 
79
                goto out;
 
80
        }
 
81
        switch (hidpp_device_get_batt_status (priv->hidpp_device)) {
 
82
        case HIDPP_DEVICE_BATT_STATUS_CHARGING:
 
83
                state = UP_DEVICE_STATE_CHARGING;
 
84
                break;
 
85
        case HIDPP_DEVICE_BATT_STATUS_DISCHARGING:
 
86
                state = UP_DEVICE_STATE_DISCHARGING;
 
87
                break;
 
88
        case HIDPP_DEVICE_BATT_STATUS_CHARGED:
 
89
                state = UP_DEVICE_STATE_FULLY_CHARGED;
 
90
                break;
 
91
        default:
 
92
                break;
 
93
        }
 
94
        g_get_current_time (&timeval);
 
95
        g_object_set (device,
 
96
                      "is-present", hidpp_device_get_version (priv->hidpp_device) > 0,
 
97
                      "percentage", (gdouble) hidpp_device_get_batt_percentage (priv->hidpp_device),
 
98
                      "state", state,
 
99
                      "update-time", (guint64) timeval.tv_sec,
 
100
                      NULL);
 
101
out:
 
102
        return TRUE;
 
103
}
 
104
 
 
105
static UpDeviceKind
 
106
up_device_unifying_get_device_kind (UpDeviceUnifying *unifying)
 
107
{
 
108
        UpDeviceKind kind;
 
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;
 
114
                break;
 
115
        case HIDPP_DEVICE_KIND_KEYBOARD:
 
116
                kind = UP_DEVICE_KIND_KEYBOARD;
 
117
                break;
 
118
        case HIDPP_DEVICE_KIND_TABLET:
 
119
                kind = UP_DEVICE_KIND_TABLET;
 
120
                break;
 
121
        default:
 
122
                kind = UP_DEVICE_KIND_UNKNOWN;
 
123
        }
 
124
        return kind;
 
125
}
 
126
 
 
127
/**
 
128
 * up_device_unifying_coldplug:
 
129
 *
 
130
 * Return %TRUE on success, %FALSE if we failed to get data and should be removed
 
131
 **/
 
132
static gboolean
 
133
up_device_unifying_coldplug (UpDevice *device)
 
134
{
 
135
        const gchar *bus_address;
 
136
        const gchar *device_file;
 
137
        const gchar *type;
 
138
        const gchar *vendor;
 
139
        gboolean ret = FALSE;
 
140
        gchar *endptr = NULL;
 
141
        gchar *tmp;
 
142
        GError *error = NULL;
 
143
        GUdevDevice *native;
 
144
        GUdevDevice *parent = NULL;
 
145
        GUdevDevice *receiver = NULL;
 
146
        UpDeviceUnifying *unifying = UP_DEVICE_UNIFYING (device);
 
147
        GUdevClient *client = NULL;
 
148
        GList *hidraw_list = NULL;
 
149
        GList *l;
 
150
 
 
151
        native = G_UDEV_DEVICE (up_device_get_native (device));
 
152
 
 
153
        /* check if we have the right device */
 
154
        type = g_udev_device_get_property (native, "UPOWER_BATTERY_TYPE");
 
155
        if (type == NULL)
 
156
                goto out;
 
157
        if ((g_strcmp0 (type, "unifying") != 0) && (g_strcmp0 (type, "lg-wireless") != 0))
 
158
                goto out;
 
159
 
 
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, ":");
 
164
        if (tmp == NULL) {
 
165
                g_debug ("Could not get physical device index");
 
166
                goto out;
 
167
        }
 
168
 
 
169
        if (g_strcmp0 (type, "lg-wireless") == 0)
 
170
                hidpp_device_set_index (unifying->priv->hidpp_device, 1);
 
171
        else {
 
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);
 
176
                        goto out;
 
177
                }
 
178
        }
 
179
 
 
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;
 
188
                        GDir* dir;
 
189
 
 
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)
 
192
                                continue;
 
193
 
 
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)),
 
196
                                        "usbmisc", NULL);
 
197
                        dir = g_dir_open (tmp, 0, &error);
 
198
                        g_free(tmp);
 
199
                        if (error) {
 
200
                                g_clear_error(&error);
 
201
                                continue;
 
202
                        }
 
203
                        while ( (filename = g_dir_read_name(dir)) ) {
 
204
                                if (g_ascii_strncasecmp(filename, "hiddev", 6) == 0) {
 
205
                                        receiver_found = TRUE;
 
206
                                        break;
 
207
                                }
 
208
                        }
 
209
                        g_dir_close(dir);
 
210
 
 
211
                        if (!receiver_found)
 
212
                                continue;
 
213
                } else {
 
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)
 
216
                                continue;
 
217
                }
 
218
                receiver = g_object_ref (l->data);
 
219
                break;
 
220
        }
 
221
        if (receiver == NULL) {
 
222
                g_debug ("Unable to find an hidraw device for Unifying receiver");
 
223
                return FALSE;
 
224
        }
 
225
 
 
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");
 
230
                goto out;
 
231
        }
 
232
        g_debug ("Using Unifying receiver hidraw device file: %s", device_file);
 
233
        hidpp_device_set_hidraw_device (unifying->priv->hidpp_device,
 
234
                                        device_file);
 
235
 
 
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,
 
241
                                    &error);
 
242
        if (!ret) {
 
243
                g_warning ("failed to coldplug unifying device: %s",
 
244
                           error->message);
 
245
                g_error_free (error);
 
246
                goto out;
 
247
        }
 
248
 
 
249
        vendor = g_udev_device_get_property (native, "UPOWER_VENDOR");
 
250
        if (vendor == NULL)
 
251
                vendor = g_udev_device_get_property (native, "ID_VENDOR");
 
252
 
 
253
        /* set some default values */
 
254
        g_object_set (device,
 
255
                      "vendor", vendor,
 
256
                      "type", up_device_unifying_get_device_kind (unifying),
 
257
                      "model", hidpp_device_get_model (unifying->priv->hidpp_device),
 
258
                      "has-history", TRUE,
 
259
                      "is-rechargeable", TRUE,
 
260
                      "power-supply", FALSE,
 
261
                      NULL);
 
262
 
 
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,
 
267
                                                               device);
 
268
        ret = TRUE;
 
269
out:
 
270
        g_list_foreach (hidraw_list, (GFunc) g_object_unref, NULL);
 
271
        g_list_free (hidraw_list);
 
272
        if (parent != NULL)
 
273
                g_object_unref (parent);
 
274
        if (receiver != NULL)
 
275
                g_object_unref (receiver);
 
276
        if (client != NULL)
 
277
                g_object_unref (client);
 
278
        return ret;
 
279
}
 
280
 
 
281
/**
 
282
 * up_device_unifying_init:
 
283
 **/
 
284
static void
 
285
up_device_unifying_init (UpDeviceUnifying *unifying)
 
286
{
 
287
        unifying->priv = UP_DEVICE_UNIFYING_GET_PRIVATE (unifying);
 
288
        unifying->priv->poll_timer_id = 0;
 
289
}
 
290
 
 
291
/**
 
292
 * up_device_unifying_finalize:
 
293
 **/
 
294
static void
 
295
up_device_unifying_finalize (GObject *object)
 
296
{
 
297
        UpDeviceUnifying *unifying;
 
298
 
 
299
        g_return_if_fail (object != NULL);
 
300
        g_return_if_fail (UP_IS_DEVICE_UNIFYING (object));
 
301
 
 
302
        unifying = UP_DEVICE_UNIFYING (object);
 
303
        g_return_if_fail (unifying->priv != NULL);
 
304
 
 
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);
 
309
 
 
310
        G_OBJECT_CLASS (up_device_unifying_parent_class)->finalize (object);
 
311
}
 
312
 
 
313
/**
 
314
 * up_device_unifying_class_init:
 
315
 **/
 
316
static void
 
317
up_device_unifying_class_init (UpDeviceUnifyingClass *klass)
 
318
{
 
319
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
320
        UpDeviceClass *device_class = UP_DEVICE_CLASS (klass);
 
321
 
 
322
        object_class->finalize = up_device_unifying_finalize;
 
323
        device_class->coldplug = up_device_unifying_coldplug;
 
324
        device_class->refresh = up_device_unifying_refresh;
 
325
 
 
326
        g_type_class_add_private (klass, sizeof (UpDeviceUnifyingPrivate));
 
327
}
 
328
 
 
329
/**
 
330
 * up_device_unifying_new:
 
331
 **/
 
332
UpDeviceUnifying *
 
333
up_device_unifying_new (void)
 
334
{
 
335
        return g_object_new (UP_TYPE_DEVICE_UNIFYING, NULL);
 
336
}