mirror of
https://gitlab.freedesktop.org/upower/upower.git
synced 2026-02-04 17:40:31 +01:00
add support for old style HID UPS devices
This commit is contained in:
parent
5f0bb1e249
commit
5b950ddeb3
4 changed files with 472 additions and 0 deletions
|
|
@ -47,6 +47,7 @@ devkit_power_daemon_SOURCES = \
|
|||
dkp-device-list.h dkp-device-list.c \
|
||||
dkp-supply.h dkp-supply.c \
|
||||
dkp-csr.h dkp-csr.c \
|
||||
dkp-hid.h dkp-hid.c \
|
||||
dkp-history.h dkp-history.c \
|
||||
sysfs-utils.h sysfs-utils.c \
|
||||
main.c \
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include "dkp-device.h"
|
||||
#include "dkp-supply.h"
|
||||
#include "dkp-csr.h"
|
||||
#include "dkp-hid.h"
|
||||
#include "dkp-device-list.h"
|
||||
|
||||
#include "dkp-daemon-glue.h"
|
||||
|
|
@ -434,6 +435,13 @@ gpk_daemon_device_get (DkpDaemon *daemon, DevkitDevice *d)
|
|||
goto out;
|
||||
g_object_unref (device);
|
||||
|
||||
/* try to detect a HID UPS */
|
||||
device = DKP_DEVICE (dkp_hid_new ());
|
||||
ret = dkp_device_coldplug (device, daemon, d);
|
||||
if (ret)
|
||||
goto out;
|
||||
g_object_unref (device);
|
||||
|
||||
/* no valid USB object ;-( */
|
||||
device = NULL;
|
||||
|
||||
|
|
|
|||
408
src/dkp-hid.c
Normal file
408
src/dkp-hid.c
Normal file
|
|
@ -0,0 +1,408 @@
|
|||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
|
||||
*
|
||||
* Copyright (C) 2006-2008 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* Based on hid-ups.c: Copyright (c) 2001 Vojtech Pavlik <vojtech@ucw.cz>
|
||||
* Copyright (c) 2001 Paul Stewart <hiddev@wetlogic.net>
|
||||
*
|
||||
* 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/gi18n-lib.h>
|
||||
#include <glib-object.h>
|
||||
#include <devkit-gobject.h>
|
||||
|
||||
/* asm/types.h required for __s32 in linux/hiddev.h */
|
||||
#include <asm/types.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/hiddev.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sysfs-utils.h"
|
||||
#include "dkp-debug.h"
|
||||
#include "dkp-enum.h"
|
||||
#include "dkp-object.h"
|
||||
#include "dkp-hid.h"
|
||||
|
||||
#define DKP_HID_REFRESH_TIMEOUT 30L
|
||||
|
||||
#define DKP_HID_USAGE 0x840000
|
||||
#define DKP_HID_SERIAL 0x8400fe
|
||||
#define DKP_HID_CHEMISTRY 0x850089
|
||||
#define DKP_HID_CAPACITY_MODE 0x85002c
|
||||
#define DKP_HID_BATTERY_VOLTAGE 0x840030
|
||||
#define DKP_HID_BELOW_RCL 0x840042
|
||||
#define DKP_HID_SHUTDOWN_IMMINENT 0x840069
|
||||
#define DKP_HID_PRODUCT 0x8400fe
|
||||
#define DKP_HID_SERIAL_NUMBER 0x8400ff
|
||||
#define DKP_HID_CHARGING 0x850044
|
||||
#define DKP_HID_DISCHARGING 0x850045
|
||||
#define DKP_HID_REMAINING_CAPACITY 0x850066
|
||||
#define DKP_HID_RUNTIME_TO_EMPTY 0x850068
|
||||
#define DKP_HID_AC_PRESENT 0x8500d0
|
||||
#define DKP_HID_BATTERY_PRESENT 0x8500d1
|
||||
#define DKP_HID_DESIGN_CAPACITY 0x850083
|
||||
#define DKP_HID_DEVICE_NAME 0x850088
|
||||
#define DKP_HID_DEVICE_CHEMISTRY 0x850089
|
||||
#define DKP_HID_RECHARGEABLE 0x85008b
|
||||
#define DKP_HID_OEM_INFORMATION 0x85008f
|
||||
|
||||
struct DkpHidPrivate
|
||||
{
|
||||
guint poll_timer_id;
|
||||
int fd;
|
||||
};
|
||||
|
||||
static void dkp_hid_class_init (DkpHidClass *klass);
|
||||
|
||||
G_DEFINE_TYPE (DkpHid, dkp_hid, DKP_TYPE_DEVICE)
|
||||
#define DKP_HID_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), DKP_TYPE_HID, DkpHidPrivate))
|
||||
|
||||
static gboolean dkp_hid_refresh (DkpDevice *device);
|
||||
|
||||
/**
|
||||
* dkp_hid_is_ups:
|
||||
**/
|
||||
static gboolean
|
||||
dkp_hid_is_ups (DkpHid *hid)
|
||||
{
|
||||
guint i;
|
||||
int retval;
|
||||
gboolean ret = FALSE;
|
||||
struct hiddev_devinfo device_info;
|
||||
|
||||
/* get device info */
|
||||
retval = ioctl (hid->priv->fd, HIDIOCGDEVINFO, &device_info);
|
||||
if (retval < 0)
|
||||
dkp_debug ("error: %s", strerror (errno));
|
||||
goto out;
|
||||
|
||||
/* can we use UPS? */
|
||||
for (i = 0; i < device_info.num_applications; i++) {
|
||||
retval = ioctl(hid->priv->fd, HIDIOCAPPLICATION, i);
|
||||
if ((retval & 0xff0000) == DKP_HID_USAGE) {
|
||||
ret = TRUE;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dkp_hid_poll:
|
||||
**/
|
||||
static gboolean
|
||||
dkp_hid_poll (DkpHid *hid)
|
||||
{
|
||||
gboolean ret;
|
||||
DkpDevice *device = DKP_DEVICE (hid);
|
||||
DkpObject *obj = dkp_device_get_obj (device);
|
||||
|
||||
dkp_debug ("Polling: %s", obj->native_path);
|
||||
ret = dkp_hid_refresh (device);
|
||||
if (ret)
|
||||
dkp_device_emit_changed (device);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* dkp_hid_get_string:
|
||||
**/
|
||||
static const gchar *
|
||||
dkp_hid_get_string (DkpHid *hid, int sindex)
|
||||
{
|
||||
static struct hiddev_string_descriptor sdesc;
|
||||
|
||||
/* nothing to get */
|
||||
if (sindex == 0)
|
||||
return "";
|
||||
|
||||
sdesc.index = sindex;
|
||||
|
||||
/* failed */
|
||||
if (ioctl (hid->priv->fd, HIDIOCGSTRING, &sdesc) < 0)
|
||||
return "";
|
||||
|
||||
dkp_debug ("value: '%s'", sdesc.value);
|
||||
return sdesc.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* dkp_hid_set_obj:
|
||||
**/
|
||||
static gboolean
|
||||
dkp_hid_set_obj (DkpHid *hid, int code, int value)
|
||||
{
|
||||
const gchar *type;
|
||||
gboolean ret = TRUE;
|
||||
DkpDevice *device = DKP_DEVICE (hid);
|
||||
DkpObject *obj = dkp_device_get_obj (device);
|
||||
|
||||
switch (code) {
|
||||
case DKP_HID_REMAINING_CAPACITY:
|
||||
obj->battery_percentage = value;
|
||||
break;
|
||||
case DKP_HID_RUNTIME_TO_EMPTY:
|
||||
obj->battery_time_to_empty = value;
|
||||
break;
|
||||
case DKP_HID_CHARGING:
|
||||
if (value != 0)
|
||||
obj->battery_state = DKP_DEVICE_STATE_CHARGING;
|
||||
break;
|
||||
case DKP_HID_DISCHARGING:
|
||||
if (value != 0)
|
||||
obj->battery_state = DKP_DEVICE_STATE_DISCHARGING;
|
||||
break;
|
||||
case DKP_HID_BATTERY_PRESENT:
|
||||
obj->battery_is_present = (value != 0);
|
||||
break;
|
||||
case DKP_HID_DEVICE_NAME:
|
||||
//obj->device_name = dkp_hid_get_string (hid, value);
|
||||
break;
|
||||
case DKP_HID_CHEMISTRY:
|
||||
type = dkp_hid_get_string (hid, value);
|
||||
obj->battery_technology = dkp_acpi_to_device_technology (type);
|
||||
break;
|
||||
case DKP_HID_RECHARGEABLE:
|
||||
obj->battery_is_rechargeable = (value != 0);
|
||||
break;
|
||||
case DKP_HID_OEM_INFORMATION:
|
||||
obj->vendor = g_strdup (dkp_hid_get_string (hid, value));
|
||||
break;
|
||||
case DKP_HID_PRODUCT:
|
||||
obj->model = g_strdup (dkp_hid_get_string (hid, value));
|
||||
break;
|
||||
case DKP_HID_SERIAL_NUMBER:
|
||||
obj->serial = g_strdup (dkp_hid_get_string (hid, value));
|
||||
break;
|
||||
case DKP_HID_DESIGN_CAPACITY:
|
||||
obj->battery_energy_full_design = value;
|
||||
break;
|
||||
default:
|
||||
ret = FALSE;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dkp_hid_get_all_data:
|
||||
**/
|
||||
static gboolean
|
||||
dkp_hid_get_all_data (DkpHid *hid)
|
||||
{
|
||||
struct hiddev_report_info rinfo;
|
||||
struct hiddev_field_info finfo;
|
||||
struct hiddev_usage_ref uref;
|
||||
int rtype;
|
||||
guint i, j;
|
||||
|
||||
/* get all results */
|
||||
for (rtype = HID_REPORT_TYPE_MIN; rtype <= HID_REPORT_TYPE_MAX; rtype++) {
|
||||
rinfo.report_type = rtype;
|
||||
rinfo.report_id = HID_REPORT_ID_FIRST;
|
||||
while (ioctl (hid->priv->fd, HIDIOCGREPORTINFO, &rinfo) >= 0) {
|
||||
for (i = 0; i < rinfo.num_fields; i++) {
|
||||
memset (&finfo, 0, sizeof (finfo));
|
||||
finfo.report_type = rinfo.report_type;
|
||||
finfo.report_id = rinfo.report_id;
|
||||
finfo.field_index = i;
|
||||
ioctl (hid->priv->fd, HIDIOCGFIELDINFO, &finfo);
|
||||
|
||||
memset (&uref, 0, sizeof (uref));
|
||||
for (j = 0; j < finfo.maxusage; j++) {
|
||||
uref.report_type = finfo.report_type;
|
||||
uref.report_id = finfo.report_id;
|
||||
uref.field_index = i;
|
||||
uref.usage_index = j;
|
||||
ioctl (hid->priv->fd, HIDIOCGUCODE, &uref);
|
||||
ioctl (hid->priv->fd, HIDIOCGUSAGE, &uref);
|
||||
|
||||
/* process each */
|
||||
dkp_hid_set_obj (hid, uref.usage_code, uref.value);
|
||||
}
|
||||
}
|
||||
rinfo.report_id |= HID_REPORT_ID_NEXT;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* dkp_hid_coldplug:
|
||||
**/
|
||||
static gboolean
|
||||
dkp_hid_coldplug (DkpDevice *device)
|
||||
{
|
||||
DkpHid *hid = DKP_HID (device);
|
||||
DevkitDevice *d;
|
||||
gboolean ret = FALSE;
|
||||
gchar *device_file = NULL;
|
||||
guint dev_num;
|
||||
guint bus_num;
|
||||
DkpObject *obj = dkp_device_get_obj (device);
|
||||
|
||||
/* detect what kind of device we are */
|
||||
d = dkp_device_get_d (device);
|
||||
if (d == NULL)
|
||||
dkp_error ("could not get device");
|
||||
|
||||
/* get what USB device we are */
|
||||
bus_num = sysfs_get_int (obj->native_path, "busnum");
|
||||
dev_num = sysfs_get_int (obj->native_path, "devnum");
|
||||
|
||||
/* get correct bus numbers? */
|
||||
if (bus_num == 0 || dev_num == 0) {
|
||||
dkp_debug ("unable to get HID bus or device numbers");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* connect to the device */
|
||||
device_file = g_strdup_printf ("/dev/bus/usb/%03i/%03i", bus_num, dev_num);
|
||||
hid->priv->fd = open (device_file, O_RDWR);
|
||||
if (hid->priv->fd < 0) {
|
||||
dkp_debug ("cannot open device file %s", device_file);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* first check that we are an UPS */
|
||||
ret = dkp_hid_is_ups (hid);
|
||||
if (!ret) {
|
||||
dkp_debug ("not a HID device: %s", device_file);
|
||||
goto out;
|
||||
}
|
||||
|
||||
obj->type = DKP_DEVICE_TYPE_UPS;
|
||||
obj->battery_is_rechargeable = TRUE;
|
||||
obj->power_supply = TRUE;
|
||||
obj->battery_is_present = TRUE;
|
||||
|
||||
/* coldplug everything */
|
||||
dkp_hid_get_all_data (hid);
|
||||
|
||||
/* coldplug */
|
||||
ret = dkp_hid_refresh (device);
|
||||
out:
|
||||
g_free (device_file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dkp_hid_refresh:
|
||||
**/
|
||||
static gboolean
|
||||
dkp_hid_refresh (DkpDevice *device)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
GTimeVal time;
|
||||
guint i;
|
||||
struct hiddev_event ev[64];
|
||||
int rd;
|
||||
DkpHid *hid = DKP_HID (device);
|
||||
DkpObject *obj = dkp_device_get_obj (device);
|
||||
|
||||
/* reset time */
|
||||
g_get_current_time (&time);
|
||||
obj->update_time = time.tv_sec;
|
||||
|
||||
/* read any data */
|
||||
rd = read (hid->priv->fd, ev, sizeof (ev));
|
||||
if (rd < (int) sizeof (ev[0]))
|
||||
goto out;
|
||||
|
||||
/* process each event */
|
||||
for (i=0; i < rd / sizeof (ev[0]); i++)
|
||||
ret = dkp_hid_set_obj (hid, ev[i].hid, ev[i].value);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dkp_hid_init:
|
||||
**/
|
||||
static void
|
||||
dkp_hid_init (DkpHid *hid)
|
||||
{
|
||||
hid->priv = DKP_HID_GET_PRIVATE (hid);
|
||||
hid->priv->fd = -1;
|
||||
hid->priv->poll_timer_id = g_timeout_add_seconds (DKP_HID_REFRESH_TIMEOUT,
|
||||
(GSourceFunc) dkp_hid_poll, hid);
|
||||
}
|
||||
|
||||
/**
|
||||
* dkp_hid_finalize:
|
||||
**/
|
||||
static void
|
||||
dkp_hid_finalize (GObject *object)
|
||||
{
|
||||
DkpHid *hid;
|
||||
|
||||
g_return_if_fail (object != NULL);
|
||||
g_return_if_fail (DKP_IS_HID (object));
|
||||
|
||||
hid = DKP_HID (object);
|
||||
g_return_if_fail (hid->priv != NULL);
|
||||
|
||||
if (hid->priv->fd > 0)
|
||||
close (hid->priv->fd);
|
||||
if (hid->priv->poll_timer_id > 0)
|
||||
g_source_remove (hid->priv->poll_timer_id);
|
||||
|
||||
G_OBJECT_CLASS (dkp_hid_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
/**
|
||||
* dkp_hid_class_init:
|
||||
**/
|
||||
static void
|
||||
dkp_hid_class_init (DkpHidClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
DkpDeviceClass *device_class = DKP_DEVICE_CLASS (klass);
|
||||
|
||||
object_class->finalize = dkp_hid_finalize;
|
||||
device_class->coldplug = dkp_hid_coldplug;
|
||||
device_class->refresh = dkp_hid_refresh;
|
||||
|
||||
g_type_class_add_private (klass, sizeof (DkpHidPrivate));
|
||||
}
|
||||
|
||||
/**
|
||||
* dkp_hid_new:
|
||||
**/
|
||||
DkpHid *
|
||||
dkp_hid_new (void)
|
||||
{
|
||||
return g_object_new (DKP_TYPE_HID, NULL);
|
||||
}
|
||||
|
||||
55
src/dkp-hid.h
Normal file
55
src/dkp-hid.h
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
|
||||
*
|
||||
* 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 __DKP_HID_H__
|
||||
#define __DKP_HID_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include "dkp-device.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define DKP_TYPE_HID (dkp_hid_get_type ())
|
||||
#define DKP_HID(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), DKP_TYPE_HID, DkpHid))
|
||||
#define DKP_HID_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), DKP_TYPE_HID, DkpHidClass))
|
||||
#define DKP_IS_HID(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), DKP_TYPE_HID))
|
||||
#define DKP_IS_HID_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), DKP_TYPE_HID))
|
||||
#define DKP_HID_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), DKP_TYPE_HID, DkpHidClass))
|
||||
|
||||
typedef struct DkpHidPrivate DkpHidPrivate;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DkpDevice parent;
|
||||
DkpHidPrivate *priv;
|
||||
} DkpHid;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DkpDeviceClass parent_class;
|
||||
} DkpHidClass;
|
||||
|
||||
GType dkp_hid_get_type (void);
|
||||
DkpHid *dkp_hid_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __DKP_HID_H__ */
|
||||
|
||||
Loading…
Add table
Reference in a new issue