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
>     dera...@amd64.openbsd.org:/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:

Reply via email to