2019-10-06 01:08:06

by Mazin Rezk

[permalink] [raw]
Subject: [PATCH v3 3/4] HID: logitech: Add feature 0x0001: FeatureSet

This patch adds support for the 0x0001 (FeatureSet) feature. This feature
is used to look up the feature ID of a feature index on a device and list
the total count of features on the device.

I also added the hidpp20_get_features function which iterates through all
feature indexes on the device and stores a map of them in features an
hidpp_device struct. This function runs when an HID++ 2.0 device is probed.

Signed-off-by: Mazin Rezk <[email protected]>
---
drivers/hid/hid-logitech-hidpp.c | 92 ++++++++++++++++++++++++++++++++
1 file changed, 92 insertions(+)

diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index a0efa8a43213..64ac94c581aa 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -190,6 +190,9 @@ struct hidpp_device {

struct hidpp_battery battery;
struct hidpp_scroll_counter vertical_wheel_counter;
+
+ u16 *features;
+ u8 feature_count;
};

/* HID++ 1.0 error codes */
@@ -911,6 +914,84 @@ static int hidpp_root_get_protocol_version(struct hidpp_device *hidpp)
return 0;
}

+/* -------------------------------------------------------------------------- */
+/* 0x0001: FeatureSet */
+/* -------------------------------------------------------------------------- */
+
+#define HIDPP_PAGE_FEATURESET 0x0001
+
+#define CMD_FEATURESET_GET_COUNT 0x00
+#define CMD_FEATURESET_GET_FEATURE 0x11
+
+static int hidpp20_featureset_get_feature(struct hidpp_device *hidpp,
+ u8 featureset_index, u8 feature_index, u16 *feature_id)
+{
+ struct hidpp_report response;
+ int ret;
+
+ ret = hidpp_send_fap_command_sync(hidpp, featureset_index,
+ CMD_FEATURESET_GET_FEATURE, &feature_index, 1, &response);
+
+ if (ret)
+ return ret;
+
+ *feature_id = (response.fap.params[0] << 8) | response.fap.params[1];
+
+ return ret;
+}
+
+static int hidpp20_featureset_get_count(struct hidpp_device *hidpp,
+ u8 feature_index, u8 *count)
+{
+ struct hidpp_report response;
+ int ret;
+
+ ret = hidpp_send_fap_command_sync(hidpp, feature_index,
+ CMD_FEATURESET_GET_COUNT, NULL, 0, &response);
+
+ if (ret)
+ return ret;
+
+ *count = response.fap.params[0];
+
+ return ret;
+}
+
+static int hidpp20_get_features(struct hidpp_device *hidpp)
+{
+ int ret;
+ u8 featureset_index, featureset_type;
+ u8 i;
+
+ hidpp->feature_count = 0;
+
+ ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_FEATURESET,
+ &featureset_index, &featureset_type);
+
+ if (ret == -ENOENT) {
+ hid_warn(hidpp->hid_dev, "Unable to retrieve feature set.");
+ return 0;
+ }
+
+ if (ret)
+ return ret;
+
+ ret = hidpp20_featureset_get_count(hidpp, featureset_index,
+ &hidpp->feature_count);
+
+ if (ret)
+ return ret;
+
+ hidpp->features = devm_kzalloc(&hidpp->hid_dev->dev,
+ hidpp->feature_count * sizeof(u16), GFP_KERNEL);
+
+ for (i = 0; i < hidpp->feature_count && !ret; i++)
+ ret = hidpp20_featureset_get_feature(hidpp, featureset_index,
+ i, &(hidpp->features[i]));
+
+ return ret;
+}
+
/* -------------------------------------------------------------------------- */
/* 0x0005: GetDeviceNameType */
/* -------------------------------------------------------------------------- */
@@ -3625,6 +3706,17 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
hidpp_overwrite_name(hdev);
}

+ /* Cache feature indexes and IDs to check reports faster */
+ if (hidpp->protocol_major >= 2) {
+ if (hidpp20_get_features(hidpp)) {
+ hid_err(hdev, "%s:hidpp20_get_features returned error\n",
+ __func__);
+ goto hid_hw_init_fail;
+ }
+ } else {
+ hidpp->feature_count = 0;
+ }
+
if (connected && (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)) {
ret = wtp_get_config(hidpp);
if (ret)
--
2.23.0


2019-10-06 15:28:08

by Filipe Laíns

[permalink] [raw]
Subject: Re: [PATCH v3 3/4] HID: logitech: Add feature 0x0001: FeatureSet

On Sun, 2019-10-06 at 01:04 +0000, Mazin Rezk wrote:
> This patch adds support for the 0x0001 (FeatureSet) feature. This feature
> is used to look up the feature ID of a feature index on a device and list
> the total count of features on the device.
>
> I also added the hidpp20_get_features function which iterates through all
> feature indexes on the device and stores a map of them in features an
> hidpp_device struct. This function runs when an HID++ 2.0 device is probed.
>
> Signed-off-by: Mazin Rezk <[email protected]>
> ---
> drivers/hid/hid-logitech-hidpp.c | 92 ++++++++++++++++++++++++++++++++
> 1 file changed, 92 insertions(+)
>
> diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
> index a0efa8a43213..64ac94c581aa 100644
> --- a/drivers/hid/hid-logitech-hidpp.c
> +++ b/drivers/hid/hid-logitech-hidpp.c
> @@ -190,6 +190,9 @@ struct hidpp_device {
>
> struct hidpp_battery battery;
> struct hidpp_scroll_counter vertical_wheel_counter;
> +
> + u16 *features;
> + u8 feature_count;
> };
>
> /* HID++ 1.0 error codes */
> @@ -911,6 +914,84 @@ static int hidpp_root_get_protocol_version(struct hidpp_device *hidpp)
> return 0;
> }
>
> +/* -------------------------------------------------------------------------- */
> +/* 0x0001: FeatureSet */
> +/* -------------------------------------------------------------------------- */
> +
> +#define HIDPP_PAGE_FEATURESET 0x0001
> +
> +#define CMD_FEATURESET_GET_COUNT 0x00
> +#define CMD_FEATURESET_GET_FEATURE 0x11
> +
> +static int hidpp20_featureset_get_feature(struct hidpp_device *hidpp,

Can you change this to `hidpp20_featureset_get_feature_id` please? So
that we keep in sync with the documentation, and to avoid minor
confusion as IRoot has a `get_feature` function.

> + u8 featureset_index, u8 feature_index, u16 *feature_id)
> +{
> + struct hidpp_report response;
> + int ret;
> +
> + ret = hidpp_send_fap_command_sync(hidpp, featureset_index,
> + CMD_FEATURESET_GET_FEATURE, &feature_index, 1, &response);
> +
> + if (ret)
> + return ret;
> +
> + *feature_id = (response.fap.params[0] << 8) | response.fap.params[1];
> +
> + return ret;
> +}
> +
> +static int hidpp20_featureset_get_count(struct hidpp_device *hidpp,
> + u8 feature_index, u8 *count)
> +{
> + struct hidpp_report response;
> + int ret;
> +
> + ret = hidpp_send_fap_command_sync(hidpp, feature_index,
> + CMD_FEATURESET_GET_COUNT, NULL, 0, &response);
> +
> + if (ret)
> + return ret;
> +
> + *count = response.fap.params[0];
> +
> + return ret;
> +}

Just a nitpick but can we put this before
`hidpp20_featureset_get_feature`? This way we keep the ID order.

> +
> +static int hidpp20_get_features(struct hidpp_device *hidpp)
> +{
> + int ret;
> + u8 featureset_index, featureset_type;
> + u8 i;
> +
> + hidpp->feature_count = 0;
> +
> + ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_FEATURESET,
> + &featureset_index, &featureset_type);
> +
> + if (ret == -ENOENT) {
> + hid_warn(hidpp->hid_dev, "Unable to retrieve feature set.");
> + return 0;
> + }
> +
> + if (ret)
> + return ret;
> +
> + ret = hidpp20_featureset_get_count(hidpp, featureset_index,
> + &hidpp->feature_count);
> +
> + if (ret)
> + return ret;
> +
> + hidpp->features = devm_kzalloc(&hidpp->hid_dev->dev,
> + hidpp->feature_count * sizeof(u16), GFP_KERNEL);
> +
> + for (i = 0; i < hidpp->feature_count && !ret; i++)
> + ret = hidpp20_featureset_get_feature(hidpp, featureset_index,
> + i, &(hidpp->features[i]));
> +
> + return ret;
> +}
> +
> /* -------------------------------------------------------------------------- */
> /* 0x0005: GetDeviceNameType */
> /* -------------------------------------------------------------------------- */

Please use `DeviceNameType` here to keep in sync with the
documentation.

> @@ -3625,6 +3706,17 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
> hidpp_overwrite_name(hdev);
> }
>
> + /* Cache feature indexes and IDs to check reports faster */
> + if (hidpp->protocol_major >= 2) {
> + if (hidpp20_get_features(hidpp)) {
> + hid_err(hdev, "%s:hidpp20_get_features returned error\n",
> + __func__);
> + goto hid_hw_init_fail;
> + }
> + } else {
> + hidpp->feature_count = 0;
> + }

I have not looked at the whole code that much but is the else really
needed here?

> +
> if (connected && (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)) {
> ret = wtp_get_config(hidpp);
> if (ret)
> --
> 2.23.0
>
--
Filipe Laíns
3DCE 51D6 0930 EBA4 7858 BA41 46F6 33CB B0EB 4BF2


Attachments:
signature.asc (849.00 B)
This is a digitally signed message part

2019-10-06 19:31:11

by Mazin Rezk

[permalink] [raw]
Subject: Re: [PATCH v3 3/4] HID: logitech: Add feature 0x0001: FeatureSet

On Sunday, October 6, 2019 11:25 AM, Filipe Laíns <[email protected]> wrote:

> On Sun, 2019-10-06 at 01:04 +0000, Mazin Rezk wrote:
> > This patch adds support for the 0x0001 (FeatureSet) feature. This feature
> > is used to look up the feature ID of a feature index on a device and list
> > the total count of features on the device.
> >
> > I also added the hidpp20_get_features function which iterates through all
> > feature indexes on the device and stores a map of them in features an
> > hidpp_device struct. This function runs when an HID++ 2.0 device is probed.
> >
> > Signed-off-by: Mazin Rezk <[email protected]>
> > ---
> > drivers/hid/hid-logitech-hidpp.c | 92 ++++++++++++++++++++++++++++++++
> > 1 file changed, 92 insertions(+)
> >
> > diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
> > index a0efa8a43213..64ac94c581aa 100644
> > --- a/drivers/hid/hid-logitech-hidpp.c
> > +++ b/drivers/hid/hid-logitech-hidpp.c
> > @@ -190,6 +190,9 @@ struct hidpp_device {
> >
> > struct hidpp_battery battery;
> > struct hidpp_scroll_counter vertical_wheel_counter;
> > +
> > + u16 *features;
> > + u8 feature_count;
> > };
> >
> > /* HID++ 1.0 error codes */
> > @@ -911,6 +914,84 @@ static int hidpp_root_get_protocol_version(struct hidpp_device *hidpp)
> > return 0;
> > }
> >
> > +/* -------------------------------------------------------------------------- */
> > +/* 0x0001: FeatureSet */
> > +/* -------------------------------------------------------------------------- */
> > +
> > +#define HIDPP_PAGE_FEATURESET 0x0001
> > +
> > +#define CMD_FEATURESET_GET_COUNT 0x00
> > +#define CMD_FEATURESET_GET_FEATURE 0x11
> > +
> > +static int hidpp20_featureset_get_feature(struct hidpp_device *hidpp,
>
> Can you change this to `hidpp20_featureset_get_feature_id` please? So
> that we keep in sync with the documentation, and to avoid minor
> confusion as IRoot has a `get_feature` function.

I will change this in v4, thanks.

>
> > + u8 featureset_index, u8 feature_index, u16 *feature_id)
> > +{
> > + struct hidpp_report response;
> > + int ret;
> > +
> > + ret = hidpp_send_fap_command_sync(hidpp, featureset_index,
> > + CMD_FEATURESET_GET_FEATURE, &feature_index, 1, &response);
> > +
> > + if (ret)
> > + return ret;
> > +
> > + *feature_id = (response.fap.params[0] << 8) | response.fap.params[1];
> > +
> > + return ret;
> > +}
> > +
> > +static int hidpp20_featureset_get_count(struct hidpp_device *hidpp,
> > + u8 feature_index, u8 *count)
> > +{
> > + struct hidpp_report response;
> > + int ret;
> > +
> > + ret = hidpp_send_fap_command_sync(hidpp, feature_index,
> > + CMD_FEATURESET_GET_COUNT, NULL, 0, &response);
> > +
> > + if (ret)
> > + return ret;
> > +
> > + *count = response.fap.params[0];
> > +
> > + return ret;
> > +}
>
> Just a nitpick but can we put this before
> `hidpp20_featureset_get_feature`? This way we keep the ID order.

That makes sense. I will change this in v4, thanks.

>
> > +
> > +static int hidpp20_get_features(struct hidpp_device *hidpp)
> > +{
> > + int ret;
> > + u8 featureset_index, featureset_type;
> > + u8 i;
> > +
> > + hidpp->feature_count = 0;
> > +
> > + ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_FEATURESET,
> > + &featureset_index, &featureset_type);
> > +
> > + if (ret == -ENOENT) {
> > + hid_warn(hidpp->hid_dev, "Unable to retrieve feature set.");
> > + return 0;
> > + }
> > +
> > + if (ret)
> > + return ret;
> > +
> > + ret = hidpp20_featureset_get_count(hidpp, featureset_index,
> > + &hidpp->feature_count);
> > +
> > + if (ret)
> > + return ret;
> > +
> > + hidpp->features = devm_kzalloc(&hidpp->hid_dev->dev,
> > + hidpp->feature_count * sizeof(u16), GFP_KERNEL);
> > +
> > + for (i = 0; i < hidpp->feature_count && !ret; i++)
> > + ret = hidpp20_featureset_get_feature(hidpp, featureset_index,
> > + i, &(hidpp->features[i]));
> > +
> > + return ret;
> > +}
> > +
> > /* -------------------------------------------------------------------------- */
> > /* 0x0005: GetDeviceNameType */
> > /* -------------------------------------------------------------------------- */
>
> Please use `DeviceNameType` here to keep in sync with the
> documentation.

Since I have not modified GetDeviceNameType in this patch, I will keep it
the way it was for now. This could probably be changed in a different and
unrelated patch.

>
> > @@ -3625,6 +3706,17 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
> > hidpp_overwrite_name(hdev);
> > }
> >
> > + /* Cache feature indexes and IDs to check reports faster */
> > + if (hidpp->protocol_major >= 2) {
> > + if (hidpp20_get_features(hidpp)) {
> > + hid_err(hdev, "%s:hidpp20_get_features returned error\n",
> > + __func__);
> > + goto hid_hw_init_fail;
> > + }
> > + } else {
> > + hidpp->feature_count = 0;
> > + }
>
> I have not looked at the whole code that much but is the else really
> needed here?

I wanted to initialize feature_count to 0 if the device was either
HID++ 1.0 or did not support FeatureSet. This was so that, just in case
its features array was accessed, it would not try to check an uninitialized
array. Although, I could probably remove the else statement and set
feature_count to 0 before the if statement. I would also be able to remove
the redundant initialization statement in hidpp20_get_features.

I will make these changes in v4, thanks.

>
> > +
> > if (connected && (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)) {
> > ret = wtp_get_config(hidpp);
> > if (ret)
> > --
> > 2.23.0
> >
> --
> Filipe Laíns
> 3DCE 51D6 0930 EBA4 7858 BA41 46F6 33CB B0EB 4BF2

2019-10-07 08:10:48

by Filipe Laíns

[permalink] [raw]
Subject: Re: [PATCH v3 3/4] HID: logitech: Add feature 0x0001: FeatureSet

On Sun, 2019-10-06 at 19:29 +0000, Mazin Rezk wrote:
> > > /* -----------------------------------------------------------
> > > --------------- */
> > > /* 0x0005:
> > > GetDeviceNameType
> > > */
> > > /* -----------------------------------------------------------
> > > --------------- */
> >
> > Please use `DeviceNameType` here to keep in sync with the
> > documentation.
>
> Since I have not modified GetDeviceNameType in this patch, I will
> keep it
> the way it was for now. This could probably be changed in a different
> and
> unrelated patch.

Ah, sorry. On my quick look it seemed to be included in the patch
:facepalm:.

Thanks,
Filipe Laíns


Attachments:
signature.asc (849.00 B)
This is a digitally signed message part