-/* $OpenBSD: uhidpp.c,v 1.17 2021/08/17 05:56:24 anton Exp $ */
+/* $OpenBSD: uhidpp.c,v 1.18 2021/08/17 11:30:45 anton Exp $ */
/*
* Copyright (c) 2021 Anton Lindqvist <anton@openbsd.org>
#define HIDPP20_BATTERY_STATUS_CHARGING_DONE 0x0003
+#define HIDPP20_BATTERY_CAPABILITY_RECHARGEABLE 0x0004
+
/* HID++ 2.0 error codes. */
#define HIDPP20_ERROR 0xff
#define HIDPP20_ERROR_NO_ERROR 0x00
#define UHIDPP_NNOTIFICATIONS 4
/* Number of sensors per paired device. */
-#define UHIDPP_NSENSORS 2
+#define UHIDPP_NSENSORS 3
/* Feature access report used by the HID++ 2.0 (and greater) protocol. */
struct fap {
uint8_t b_next_level;
uint8_t b_status;
uint8_t b_nlevels;
+ uint8_t b_rechargeable;
} d_battery;
};
int hidpp20_battery_get_level_status(struct uhidpp_softc *, uint8_t, uint8_t,
uint8_t *, uint8_t *, uint8_t *);
int hidpp20_battery_get_capability(struct uhidpp_softc *, uint8_t, uint8_t,
- uint8_t *);
+ uint8_t *, uint8_t *);
int hidpp20_battery_status_is_charging(uint8_t);
int hidpp_send_validate(uint8_t, int);
uhidpp_detach(struct device *self, int flags)
{
struct uhidpp_softc *sc = (struct uhidpp_softc *)self;
- int i, j;
+ int i;
usb_rem_wait_task(sc->sc_udev, &sc->sc_task);
for (i = 0; i < UHIDPP_NDEVICES; i++) {
struct uhidpp_device *dev = &sc->sc_devices[i];
+ struct ksensor *sens = dev->d_battery.b_sens;
if (!dev->d_connected)
continue;
- for (j = 0; j < UHIDPP_NSENSORS; j++)
- sensor_detach(&sc->sc_sensdev, &dev->d_battery.b_sens[j]);
+ sensor_detach(&sc->sc_sensdev, &sens[0]);
+ sensor_detach(&sc->sc_sensdev, &sens[1]);
+ if (dev->d_battery.b_rechargeable)
+ sensor_detach(&sc->sc_sensdev, &sens[2]);
}
uhidev_close(&sc->sc_hdev);
return;
}
- error = hidpp20_battery_get_capability(sc, dev->d_id,
- dev->d_battery.b_feature_idx, &dev->d_battery.b_nlevels);
+ error = hidpp20_battery_get_capability(sc,
+ dev->d_id, dev->d_battery.b_feature_idx,
+ &dev->d_battery.b_nlevels, &dev->d_battery.b_rechargeable);
if (error) {
DPRINTF("%s: battery capability failure: device_id=%d, "
"error=%d\n", __func__, dev->d_id, error);
sens->value = dev->d_battery.b_nlevels;
sensor_attach(&sc->sc_sensdev, sens);
+ if (dev->d_battery.b_rechargeable) {
+ sens = &dev->d_battery.b_sens[2];
+ strlcpy(sens->desc, "charger", sizeof(sens->desc));
+ sens->type = SENSOR_INDICATOR;
+ sens->value = 0;
+ sensor_attach(&sc->sc_sensdev, sens);
+ }
+
if (sc->sc_senstsk == NULL) {
/*
* The mutex must be temporarily released while calling
void
uhidpp_device_refresh(struct uhidpp_softc *sc, struct uhidpp_device *dev)
{
- int error;
-
MUTEX_ASSERT_LOCKED(&sc->sc_mtx);
if (dev->d_major >= 2) {
+ int charging, error;
+
error = hidpp20_battery_get_level_status(sc, dev->d_id,
dev->d_battery.b_feature_idx,
&dev->d_battery.b_level, &dev->d_battery.b_next_level,
return;
}
+ charging = hidpp20_battery_status_is_charging(
+ dev->d_battery.b_status);
+
dev->d_battery.b_sens[0].value = dev->d_battery.b_level * 1000;
dev->d_battery.b_sens[0].flags &= ~SENSOR_FUNKNOWN;
if (dev->d_battery.b_nlevels < 10) {
* it even further. Unless the battery is charging in
* which the level cannot be trusted.
*/
- if (hidpp20_battery_status_is_charging(
- dev->d_battery.b_status))
+ if (charging)
dev->d_battery.b_sens[0].status = SENSOR_S_UNKNOWN;
else if (dev->d_battery.b_level <= 10)
dev->d_battery.b_sens[0].status = SENSOR_S_CRIT;
*/
dev->d_battery.b_sens[0].status = SENSOR_S_UNKNOWN;
}
+
+ if (dev->d_battery.b_rechargeable)
+ dev->d_battery.b_sens[2].value = charging;
}
}
int
hidpp20_battery_get_capability(struct uhidpp_softc *sc, uint8_t device_id,
- uint8_t feature_idx, uint8_t *nlevels)
+ uint8_t feature_idx, uint8_t *nlevels, uint8_t *rechargeable)
{
struct uhidpp_report resp;
int error;
if (error)
return error;
*nlevels = resp.fap.params[0];
+ *rechargeable = resp.fap.params[1] &
+ HIDPP20_BATTERY_CAPABILITY_RECHARGEABLE;
return 0;
}