Hi,
On Mon, Feb 08, 2021 at 02:50:39PM -0800, Anindya Mukherjee wrote:
> Hi, I have a Logitech M570 which seems to be handled by this new driver.
> However I don't see any battery level information.
>
> dmesg:
> uhidpp0 at uhidev4 device 1 mouse "M570" serial ef-81-ff-80
>
> sysctl kern.version:
> kern.version=OpenBSD 6.8-current (GENERIC.MP) #313: Fri Feb 5 18:31:44 MST
> 2021
> [email protected]:/usr/src/sys/arch/amd64/compile/GENERIC.MP
>
> hw.sensors.uhidpp0 does not seem to exist.
>
> Regards,
> Anindya
>
Could you try the following diff and send me the complete dmesg. I've
also prepared an amd64 kernel with the patch applied:
https://www.basename.se/tmp/bsd.uhidpp.battery
diff --git sys/dev/usb/uhidpp.c sys/dev/usb/uhidpp.c
index b041d86fecd..27f6137ec06 100644
--- sys/dev/usb/uhidpp.c
+++ sys/dev/usb/uhidpp.c
@@ -29,7 +29,7 @@
#include <dev/usb/usbdevs.h>
#include <dev/usb/uhidev.h>
-/* #define UHIDPP_DEBUG */
+#define UHIDPP_DEBUG
#ifdef UHIDPP_DEBUG
#define DPRINTF(x...) do { \
@@ -84,12 +84,16 @@ int uhidpp_debug = 1;
#define HIDPP_GET_LONG_REGISTER 0x83
#define HIDPP_REG_ENABLE_REPORTS 0x00
+#define HIDPP_REG_BATTERY_STATUS 0x07
#define HIDPP_REG_PAIRING_INFORMATION 0xb5
#define HIDPP_NOTIF_DEVICE_BATTERY_STATUS (1 << 4)
#define HIDPP_NOTIF_RECEIVER_WIRELESS (1 << 0)
#define HIDPP_NOTIF_RECEIVER_SOFTWARE_PRESENT (1 << 3)
+/* Number of battery levels supported by HID++ 1.0 devices. */
+#define HIDPP_BATTERY_NLEVELS 7
+
/* HID++ 1.0 error codes. */
#define HIDPP_ERROR 0x8f
#define HIDPP_ERROR_SUCCESS 0x00
@@ -112,7 +116,6 @@ int uhidpp_debug = 1;
* greater than zero which is reserved for notifications.
*/
#define HIDPP_SOFTWARE_ID 0x01
-#define HIDPP_SOFTWARE_ID_MASK 0x0f
#define HIDPP_SOFTWARE_ID_LEN 4
#define HIDPP20_FEAT_ROOT_IDX 0x00
@@ -154,8 +157,8 @@ int uhidpp_debug = 1;
/* Feature access report used by the HID++ 2.0 (and greater) protocol. */
struct fap {
- uint8_t feature_index;
- uint8_t funcindex_clientid;
+ uint8_t feature_idx;
+ uint8_t funcidx_swid;
uint8_t params[HIDPP_REPORT_LONG_PARAMS_MAX];
};
@@ -185,6 +188,8 @@ struct uhidpp_notification {
struct uhidpp_device {
uint8_t d_id;
uint8_t d_connected;
+ uint8_t d_major;
+ uint8_t d_minor;
struct {
struct ksensor b_sens[UHIDPP_NSENSORS];
uint8_t b_feature_idx;
@@ -237,8 +242,10 @@ struct uhidpp_notification
*uhidpp_claim_notification(struct uhidpp_softc *);
int uhidpp_consume_notification(struct uhidpp_softc *, struct uhidpp_report *);
int uhidpp_is_notification(struct uhidpp_softc *, struct uhidpp_report *);
-int hidpp_get_protocol_version(struct uhidpp_softc *, uint8_t, int *, int *);
+int hidpp_get_protocol_version(struct uhidpp_softc *, uint8_t, uint8_t *,
+ uint8_t *);
+int hidpp10_get_battery_status(struct uhidpp_softc *, uint8_t, uint8_t *);
int hidpp10_get_name(struct uhidpp_softc *, uint8_t, char *, size_t);
int hidpp10_get_serial(struct uhidpp_softc *, uint8_t, uint8_t *, size_t);
int hidpp10_get_type(struct uhidpp_softc *, uint8_t, const char **);
@@ -520,7 +527,7 @@ void
uhidpp_device_connect(struct uhidpp_softc *sc, struct uhidpp_device *dev)
{
struct ksensor *sens;
- int error, major, minor;
+ int error;
uint8_t feature_type;
MUTEX_ASSERT_LOCKED(&sc->sc_mtx);
@@ -529,30 +536,40 @@ uhidpp_device_connect(struct uhidpp_softc *sc, struct
uhidpp_device *dev)
if (dev->d_connected)
return;
- error = hidpp_get_protocol_version(sc, dev->d_id, &major, &minor);
+ error = hidpp_get_protocol_version(sc, dev->d_id,
+ &dev->d_major, &dev->d_minor);
if (error) {
- DPRINTF("%s: protocol version failure: device_id=%d,
error=%d\n",
+ DPRINTF("%s: protocol version failure: device_id=%d, "
+ "error=%d\n",
__func__, dev->d_id, error);
return;
}
DPRINTF("%s: device_id=%d, version=%d.%d\n",
- __func__, dev->d_id, major, minor);
+ __func__, dev->d_id, dev->d_major, dev->d_minor);
- error = hidpp20_root_get_feature(sc, dev->d_id,
- HIDPP20_FEAT_BATTERY_IDX,
- &dev->d_battery.b_feature_idx, &feature_type);
- if (error) {
- DPRINTF("%s: battery feature index failure: device_id=%d, "
- "error=%d\n", __func__, dev->d_id, error);
- return;
- }
+ if (dev->d_major >= 2) {
+ error = hidpp20_root_get_feature(sc, dev->d_id,
+ HIDPP20_FEAT_BATTERY_IDX,
+ &dev->d_battery.b_feature_idx, &feature_type);
+ if (error) {
+ DPRINTF("%s: battery feature index failure: "
+ "device_id=%d, error=%d\n",
+ __func__, dev->d_id, error);
+ return;
+ }
- error = hidpp20_battery_get_capability(sc, dev->d_id,
- dev->d_battery.b_feature_idx, &dev->d_battery.b_nlevels);
- if (error) {
- DPRINTF("%s: battery capability failure: device_id=%d, "
- "error=%d\n", __func__, dev->d_id, error);
+ error = hidpp20_battery_get_capability(sc, dev->d_id,
+ dev->d_battery.b_feature_idx, &dev->d_battery.b_nlevels);
+ if (error) {
+ DPRINTF("%s: battery capability failure: device_id=%d, "
+ "error=%d\n", __func__, dev->d_id, error);
+ return;
+ }
+
+ } else if (dev->d_major == 1) {
+ dev->d_battery.b_nlevels = HIDPP_BATTERY_NLEVELS;
+ } else {
return;
}
@@ -579,44 +596,58 @@ uhidpp_device_refresh(struct uhidpp_softc *sc, struct
uhidpp_device *dev)
MUTEX_ASSERT_LOCKED(&sc->sc_mtx);
- 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,
- &dev->d_battery.b_status);
- if (error) {
- DPRINTF("%s: battery level status failure: device_id=%d, "
- "error=%d\n", __func__, dev->d_id, error);
- return;
- }
+ if (dev->d_major >= 2) {
+ 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,
+ &dev->d_battery.b_status);
+ if (error) {
+ DPRINTF("%s: battery status failure: device_id=%d, "
+ "error=%d\n",
+ __func__, dev->d_id, error);
+ return;
+ }
- 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) {
- /*
- * According to the HID++ 2.0 specification, less than 10 levels
- * should be mapped to the following 4 levels:
- *
- * [0, 10] critical
- * [11, 30] low
- * [31, 80] good
- * [81, 100] full
- *
- * Since sensors are limited to 3 valid statuses, clamp it even
- * further.
- */
- if (dev->d_battery.b_level <= 10)
- dev->d_battery.b_sens[0].status = SENSOR_S_CRIT;
- else if (dev->d_battery.b_level <= 30)
- dev->d_battery.b_sens[0].status = SENSOR_S_WARN;
- else
- dev->d_battery.b_sens[0].status = SENSOR_S_OK;
+ 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) {
+ /*
+ * According to the HID++ 2.0 specification, less than
+ * 10 levels should be mapped to the following 4 levels:
+ *
+ * [0, 10] critical
+ * [11, 30] low
+ * [31, 80] good
+ * [81, 100] full
+ *
+ * Since sensors are limited to 3 valid statuses, clamp
+ * it even further.
+ */
+ if (dev->d_battery.b_level <= 10)
+ dev->d_battery.b_sens[0].status = SENSOR_S_CRIT;
+ else if (dev->d_battery.b_level <= 30)
+ dev->d_battery.b_sens[0].status = SENSOR_S_WARN;
+ else
+ dev->d_battery.b_sens[0].status = SENSOR_S_OK;
+ } else {
+ /*
+ * XXX the device supports battery mileage. The current
+ * level must be checked against resp.fap.params[3]
+ * given by hidpp20_battery_get_capability().
+ */
+ dev->d_battery.b_sens[0].status = SENSOR_S_UNKNOWN;
+ }
} else {
- /*
- * XXX the device supports battery mileage. The current level
- * must be checked against resp.fap.params[3] given by
- * hidpp20_battery_get_capability().
- */
- dev->d_battery.b_sens[0].status = SENSOR_S_UNKNOWN;
+ error = hidpp10_get_battery_status(sc, dev->d_id,
+ &dev->d_battery.b_level);
+ if (error) {
+ DPRINTF("%s: battery status failure: device_id=%d, "
+ "error=%d\n",
+ __func__, dev->d_id, error);
+ return;
+ }
+ dev->d_battery.b_sens[0].value = dev->d_battery.b_level * 1000;
+ dev->d_battery.b_sens[0].flags &= ~SENSOR_FUNKNOWN;
}
}
@@ -692,9 +723,9 @@ uhidpp_is_notification(struct uhidpp_softc *sc, struct
uhidpp_report *rep)
/* An error must always be a response. */
if ((rep->rap.sub_id == HIDPP_ERROR ||
- rep->fap.feature_index == HIDPP20_ERROR) &&
- rep->fap.funcindex_clientid == sc->sc_req->fap.feature_index &&
- rep->fap.params[0] == sc->sc_req->fap.funcindex_clientid)
+ rep->fap.feature_idx == HIDPP20_ERROR) &&
+ rep->fap.funcidx_swid == sc->sc_req->fap.feature_idx &&
+ rep->fap.params[0] == sc->sc_req->fap.funcidx_swid)
return 0;
return 1;
@@ -702,7 +733,7 @@ uhidpp_is_notification(struct uhidpp_softc *sc, struct
uhidpp_report *rep)
int
hidpp_get_protocol_version(struct uhidpp_softc *sc, uint8_t device_id,
- int *major, int *minor)
+ uint8_t *major, uint8_t *minor)
{
struct uhidpp_report resp;
uint8_t params[3] = { 0, 0, HIDPP_FEAT_ROOT_PING_DATA };
@@ -729,6 +760,37 @@ hidpp_get_protocol_version(struct uhidpp_softc *sc,
uint8_t device_id,
return 0;
}
+int
+hidpp10_get_battery_status(struct uhidpp_softc *sc, uint8_t device_id,
+ uint8_t *level)
+{
+ struct uhidpp_report resp;
+ int error;
+
+ error = hidpp_send_rap_report(sc,
+ HIDPP_REPORT_ID_SHORT,
+ device_id,
+ HIDPP_GET_REGISTER,
+ HIDPP_REG_BATTERY_STATUS,
+ NULL, 0, &resp);
+ DPRINTF("XXX %s: error=%d, device_id=%d\n",
+ __func__, error, device_id);
+ if (error)
+ return error;
+ if (resp.rap.params[0] < 1 ||
+ resp.rap.params[0] > HIDPP_BATTERY_NLEVELS)
+ return -ERANGE;
+
+ DPRINTF("XXX %s: p0=%x, p1=%x, p2=%x, device_id=%d\n",
+ __func__,
+ resp.rap.params[0],
+ resp.rap.params[1],
+ resp.rap.params[2],
+ device_id);
+ *level = (resp.rap.params[0] * 100) / HIDPP_BATTERY_NLEVELS;
+ return 0;
+}
+
int
hidpp10_get_name(struct uhidpp_softc *sc, uint8_t device_id,
char *buf, size_t bufsiz)
@@ -848,7 +910,7 @@ hidpp10_enable_notifications(struct uhidpp_softc *sc,
uint8_t device_id)
int
hidpp20_root_get_feature(struct uhidpp_softc *sc, uint8_t device_id,
- uint16_t feature, uint8_t *feature_index, uint8_t *feature_type)
+ uint16_t feature, uint8_t *feature_idx, uint8_t *feature_type)
{
struct uhidpp_report resp;
uint8_t params[2] = { feature >> 8, feature & 0xff };
@@ -866,14 +928,14 @@ hidpp20_root_get_feature(struct uhidpp_softc *sc, uint8_t
device_id,
if (resp.fap.params[0] == 0)
return -ENOENT;
- *feature_index = resp.fap.params[0];
+ *feature_idx = resp.fap.params[0];
*feature_type = resp.fap.params[1];
return 0;
}
int
hidpp20_battery_get_level_status(struct uhidpp_softc *sc, uint8_t device_id,
- uint8_t feature_index, uint8_t *level, uint8_t *next_level, uint8_t
*status)
+ uint8_t feature_idx, uint8_t *level, uint8_t *next_level, uint8_t *status)
{
struct uhidpp_report resp;
int error;
@@ -881,7 +943,7 @@ hidpp20_battery_get_level_status(struct uhidpp_softc *sc,
uint8_t device_id,
error = hidpp_send_fap_report(sc,
HIDPP_REPORT_ID_LONG,
device_id,
- feature_index,
+ feature_idx,
HIDPP20_FEAT_BATTERY_LEVEL_FUNC,
NULL, 0, &resp);
if (error)
@@ -895,7 +957,7 @@ hidpp20_battery_get_level_status(struct uhidpp_softc *sc,
uint8_t device_id,
int
hidpp20_battery_get_capability(struct uhidpp_softc *sc, uint8_t device_id,
- uint8_t feature_index, uint8_t *nlevels)
+ uint8_t feature_idx, uint8_t *nlevels)
{
struct uhidpp_report resp;
int error;
@@ -903,7 +965,7 @@ hidpp20_battery_get_capability(struct uhidpp_softc *sc,
uint8_t device_id,
error = hidpp_send_fap_report(sc,
HIDPP_REPORT_ID_LONG,
device_id,
- feature_index,
+ feature_idx,
HIDPP20_FEAT_BATTERY_CAPABILITY_FUNC,
NULL, 0, &resp);
if (error)
@@ -929,7 +991,7 @@ hidpp_send_validate(uint8_t report_id, int nparams)
int
hidpp_send_fap_report(struct uhidpp_softc *sc, uint8_t report_id,
- uint8_t device_id, uint8_t feature_index, uint8_t funcindex_clientid,
+ uint8_t device_id, uint8_t feature_idx, uint8_t funcidx_swid,
uint8_t *params, int nparams, struct uhidpp_report *resp)
{
struct uhidpp_report req;
@@ -941,9 +1003,9 @@ hidpp_send_fap_report(struct uhidpp_softc *sc, uint8_t
report_id,
memset(&req, 0, sizeof(req));
req.device_id = device_id;
- req.fap.feature_index = feature_index;
- req.fap.funcindex_clientid =
- (funcindex_clientid << HIDPP_SOFTWARE_ID_LEN) | HIDPP_SOFTWARE_ID;
+ req.fap.feature_idx = feature_idx;
+ req.fap.funcidx_swid =
+ (funcidx_swid << HIDPP_SOFTWARE_ID_LEN) | HIDPP_SOFTWARE_ID;
memcpy(req.fap.params, params, nparams);
return hidpp_send_report(sc, report_id, &req, resp);
}
@@ -1024,7 +1086,7 @@ hidpp_send_report(struct uhidpp_softc *sc, uint8_t
report_id,
resp->rap.sub_id == HIDPP_ERROR)
error = resp->rap.params[1];
else if (sc->sc_resp_state == HIDPP_REPORT_ID_LONG &&
- resp->fap.feature_index == HIDPP20_ERROR)
+ resp->fap.feature_idx == HIDPP20_ERROR)
error = resp->fap.params[1];
out: