All of lore.kernel.org
 help / color / mirror / Atom feed
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
To: Kenneth Albanowski <kenalba@google.com>
Cc: "open list:HID CORE LAYER" <linux-input@vger.kernel.org>,
	Dmitry Torokhov <dmitry.torokhov@gmail.com>,
	Jiri Kosina <jikos@kernel.org>,
	Peter Hutterer <peter.hutterer@who-t.net>,
	Jason Gerecke <Jason.Gerecke@wacom.com>
Subject: Re: Supporting 64-bit Digitizer Serial Numbers?
Date: Thu, 25 Mar 2021 09:35:33 +0100	[thread overview]
Message-ID: <CAO-hwJ+6g9ADRpShG_HbQi5PGv6PLp-1wxJP7CSLT+1uJLB9OA@mail.gmail.com> (raw)
In-Reply-To: <CALvoSf7L2tkrdg_rF0ZqbUv-H2TXnEudjSDUrts+MUs=Lvhpeg@mail.gmail.com>

Hi Kenneth,

On Wed, Mar 24, 2021 at 8:53 PM Kenneth Albanowski <kenalba@google.com> wrote:
>
> Hi folks,
>
> I'm looking at being able to retrieve an accurate (not mangled or
> truncated) Digitizer.Transducer Serial Number from user-space, primarily
> through the power_supply node constructed for HID devices which expose
> Battery Strength.
>
> For the digitizers I'm looking at (USI) the Serial Number is a 64-bit
> report field, making it not fit directly into evdev, or the hid-input
> core.

Thanks for raising that issue. Before I jump into commenting on your
PoC, I'd like to ask you to provide the report descriptor of this
particular device (ideally with hid-recorder from the hid-tolls repo
below).
AFAICT, the HID spec we currently implement doesn't allow for data of
more than 32 bits (section 6.2.2.2 of
https://www.usb.org/sites/default/files/hid1_11.pdf).
The main problem is that a field is usually associated with a logical
max, and this part makes us limit the field up to 32bits.

There is a "long items" section right after (6.2.2.3) that allows for
longer data, and I don't think the current implementation supports it.

One other thing: this whole problem is very much a good candidate for
adding regression tests on
https://gitlab.freedesktop.org/libevdev/hid-tools.

So I'd be glad if we can work around the problem in the kernel *and*
add the matching test in hid-tools so we don't break this in the
future.

More comments inlined...

>
> I'm appending a proof-of-concept which implements this; I describe the
> details below. (This is based on 5.4, but it looks clean for 5.10 as
> well as relatively straightforward to backport.)
>
> I'd appreciate any feedback on this approach.
>
> My thought is to perform minimal modifications to allow hid-core to
> transfer reports up to 64-bits in size to hid-input, so that it can
> process this field and emit it to the power_supply integration, as well
> as through classic MSC_SERIAL (for the low 32 bits) and a new
> MSC_SERIAL2 (the upper bits) for applications which want it inline with
> stylus event data.

The wacom driver already has this problem and handles it in a creative
way (as usual ;-P)
If I am not mistaken, it splits the 64 bits serial on 2 events as
well: MSC_SERIAL and ABS_MISC (Jason might correct me here).

I am not saying this is what needs to be done, but just what some
userspace tools already expect.


>
> hid_field.value is expanded to an s64 array from s32, and there are
> a few knock-on effects to code that holds pointers to these fields.
> No other interfaces, in-kernel, or user-space, are modified to support
> HID reports/evdev events > 32 bits.

I also think both problems are orthogonal (which is why you haven't
tried to change the evdev protocol).

I don't think we can do much on the evdev side to support 64 bits or
bigger data.
Dmitry and Peter might find a good way to work around that, but I'm OK
with adding MSC_SERIAL_2 from my point of view.

>
> The Transducer Serial Number would show up as in the power_supply as a
> serial_number of "DG:0123456789ABCDEF" (or however many hex digits are
> warranted by the report size), and "DG:" being a fixed prefix -- we do
> know it is a digitizer.
>
> I realize this doesn't provide a scalable solution in the
> hid-core/hid-input code for (hypothetical) fields larger than 64 bits,
> although extending evdev with MSC_SERIAL3, 4, etc. would be trivial. (I
> don't have a good sense of how common these larger fields are, although
> obviously the code has survived until now with only 32-bit support, and
> one comment saying that anything larger than 16-bit is unusual.)

I would prefer having a generic solution for items longer than 32 bits
instead of having a special case for 64 bits only.

The spec allows for items longer than 32 bits (still section 6.2.2.3
of the HID spec) so we should probably handle that case in a generic
way to not have to deal with 128 bits next time a creative device
maker wants to use it.
The nice thing about the hid-tools test suite is that we can be
creative and produce this 128 bits new device, and have the tests for
it already :)

>
> (The other approach I was looking at was leaving hid_field.value
> unchanged, and instead just having hid-core recognize this particular
> 64 bit field, edit the hid_usage to turn it into a 2-count 32-bit field,
> apply a unique usage code to the second half, and then have hid-input
> recognize these usages and paste everything back together. This is
> scalable to larger fields, but is putting an unprecedented amount of
> magic in hid-core.)

Not really. There is already a lot of magic in hid-core, and handling
longer-than-32bits doesn't seem that far away. The report descriptor
should give us all the information we need, so we can surely have a
special case for long items and data. Also hid-input doesn't have to
be tied to evdev. So nothing prevents us to mark the field as being a
long one, and change the internal representation of the various 32
bits chunks of its data.

>
> The other change is MSC_SERIAL2 would be added: in the specific case of
> Usage(Digitizer.Transducer Serial Number) being present with
> report_size > 32 then MSC_SERIAL is reliably the full lowest 32 bits,
> and MSC_SERIAL2 is the next set of 32 bits; no clamping or scaling
> applied, regardless of what the descriptor says. Both MSC_SERIAL* are
> emitted for every hid record, there is no caching. If report_size <=
> 32, then there is no difference to existing behaviour, only MSC_SERIAL
> is emitted. I'm assuming the cost of one additional event per sync, for
> stylus data, is negligible.

I am not in the best position to comment, but as mentioned previously,
it works for me.

>
> This does potentially alter the generation of MSC_SERIAL on existing
> devices, but only ones where the report_size > 32 bits and the min/max
> is not 0/~0 -- user space would see unclamped values and conceivably
> could be surprised with a larger value in MSC_SERIAL than previously
> seen.

Honestly it shouldn't introduce any regressions. I still have to work
on the tablet side of the regression tests, but so far only Wacom was
reliably sending serial numbers (and bigger than 32 bits). So I am not
worried from this side of things.

>
> If changing MSC_SERIAL is deemed too risky for compatibility, then it's
> easy to just leave MSC_SERIAL as-is, and put in a separate MSC_SERIAL1
> (MSC_SERIAL0?) that has the pristine low bits -- just at a cost of yet
> one more MSC_ field per report, and using up the last MSC_ bit before
> we need to bump MSC_MAX.
>
> This approach doesn't affect Wacom evdev events at all, all of that
> logic is separate from hid-input.

There is a whole ecosystem for wacom, but we are pretty much in
control of all the pieces. So I would prefer involving wacom from the
beginning, and have a common representation to the user space.

Besides that, I skimmed through the  patch below. I do have comments,
but in addition to the above, they are mostly "hey this hunk should be
in its own separate patch". But I guess the final submission will have
this separation, so there is no real point in going too deep in the
details IMO.

Cheers,
Benjamin

>
> Kind regards and good health,
> - Kenneth Albanowski
>
> From 9948f77d758c5688d5ac5dee8f7218aa36cbd20d Mon Sep 17 00:00:00 2001
> From: Kenneth Albanowski <kenalba@google.com>
> Date: Mon, 22 Mar 2021 11:40:13 -0700
> Subject: [PATCH] input: limited 64-bit usages; MSC_SERIAL2,
>  POWER_SUPPLY_SERIAL_NUMBER
>
> Extend hid-core to process 64-bit usages, updating hid-input
> to recognize digitizer transducer serial numbers up to 64 bits,
> emitting MSC_SERIAL and MSC_SERIAL2 (new) for second 32-bit word.
>
> 64-bit usages are only fed to hid-input, all other existing
> frameworks and interfaces only see the traditional 32-bit
> truncated values; the majority of hid-input still only uses
> traditional 32-bit clamped values.
>
> Behaviour is changed only for HID reports that have
> Usage(Digitizer.TransducerSerialNumber) where size > 32 bits;
> logical min/max are no longer used to clamp the value, so
> MSC_SERIAL may be different from prior logic and now emits
> entire lowest 32-bits, instead of clamped value. Upper bits
> (32-64) are emitted to MSC_SERIAL2, also unclamped.
>
> power_supply integration extended to emit
> Digitizer.TransducerSerialNumber as POWER_SUPPLY_SERIAL_NUMBER
> in format: "DG:0123456789ABCDEF", with appropriate number of
> digits for actual field length.
>
> Change-Id: Ic8f9c90081f324ff76f34b0906bca1fcd5eac06a
> ---
>  Documentation/hid/hiddev.rst           |   6 +-
>  drivers/hid/hid-core.c                 |  80 +++++++++++---------
>  drivers/hid/hid-debug.c                |   4 +-
>  drivers/hid/hid-input.c                | 101 +++++++++++++++++++++++--
>  drivers/hid/hid-multitouch.c           |  22 +++---
>  drivers/hid/hid-sony.c                 |   2 +-
>  drivers/hid/usbhid/hid-pidff.c         |   2 +-
>  include/linux/hid-debug.h              |   2 +-
>  include/linux/hid.h                    |  13 +++-
>  include/uapi/linux/input-event-codes.h |   3 +-
>  10 files changed, 173 insertions(+), 62 deletions(-)
>
> diff --git a/Documentation/hid/hiddev.rst b/Documentation/hid/hiddev.rst
> index 209e6ba4e019e..06eee00847e50 100644
> --- a/Documentation/hid/hiddev.rst
> +++ b/Documentation/hid/hiddev.rst
> @@ -72,8 +72,10 @@ The hiddev API uses a read() interface, and a set
> of ioctl() calls.
>
>  HID devices exchange data with the host computer using data
>  bundles called "reports".  Each report is divided into "fields",
> -each of which can have one or more "usages".  In the hid-core,
> -each one of these usages has a single signed 32 bit value.
> +each of which can have one or more "usages". Each of these usages
> +is a single value, usually a signed 32 bit value, which is what
> +the hiddev API supports. (hid-core can process 64 bit values, but
> +these are not currently exposed through hiddev.)
>
>  read():
>  -------
> diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
> index 1489f49dc53d0..5f4c7f06d0e96 100644
> --- a/drivers/hid/hid-core.c
> +++ b/drivers/hid/hid-core.c
> @@ -101,14 +101,14 @@ static struct hid_field
> *hid_register_field(struct hid_report *report, unsigned
>
>   field = kzalloc((sizeof(struct hid_field) +
>   usages * sizeof(struct hid_usage) +
> - usages * sizeof(unsigned)), GFP_KERNEL);
> + usages * sizeof(s64)), GFP_KERNEL);
>   if (!field)
>   return NULL;
>
>   field->index = report->maxfield++;
>   report->field[field->index] = field;
>   field->usage = (struct hid_usage *)(field + 1);
> - field->value = (s32 *)(field->usage + usages);
> + field->value = (s64 *)(field->usage + usages);
>   field->report = report;
>
>   return field;
> @@ -337,7 +337,8 @@ static int hid_add_field(struct hid_parser
> *parser, unsigned report_type, unsign
>  }
>
>  /*
> - * Read data value from item.
> + * Read data value from global items, which are
> + * a maximum of 32 bits in size.
>   */
>
>  static u32 item_udata(struct hid_item *item)
> @@ -763,7 +764,7 @@ static u8 *fetch_item(__u8 *start, __u8 *end,
> struct hid_item *item)
>   return start;
>
>   case 3:
> - item->size++;
> + item->size = 4;
>   if ((end - start) < 4)
>   return NULL;
>   item->data.u32 = get_unaligned_le32(start);
> @@ -1016,7 +1017,7 @@ static int hid_calculate_multiplier(struct
> hid_device *hid,
>       struct hid_field *multiplier)
>  {
>   int m;
> - __s32 v = *multiplier->value;
> + __s64 v = *multiplier->value;
>   __s32 lmin = multiplier->logical_minimum;
>   __s32 lmax = multiplier->logical_maximum;
>   __s32 pmin = multiplier->physical_minimum;
> @@ -1299,27 +1300,17 @@ int hid_open_report(struct hid_device *device)
>  }
>  EXPORT_SYMBOL_GPL(hid_open_report);
>
> -/*
> - * Convert a signed n-bit integer to signed 32-bit integer. Common
> - * cases are done through the compiler, the screwed things has to be
> - * done by hand.
> - */
> -
> -static s32 snto32(__u32 value, unsigned n)
> +s32 hid_snto32(__u32 value, unsigned n)
>  {
> - switch (n) {
> - case 8:  return ((__s8)value);
> - case 16: return ((__s16)value);
> - case 32: return ((__s32)value);
> - }
> - return value & (1 << (n - 1)) ? value | (~0U << n) : value;
> + return sign_extend32(value, n);
>  }
> +EXPORT_SYMBOL_GPL(hid_snto32);
>
> -s32 hid_snto32(__u32 value, unsigned n)
> +s64 hid_snto64(__u64 value, unsigned n)
>  {
> - return snto32(value, n);
> + return sign_extend64(value, n);
>  }
> -EXPORT_SYMBOL_GPL(hid_snto32);
> +EXPORT_SYMBOL_GPL(hid_snto64);
>
>  /*
>   * Convert a signed 32-bit integer to a signed n-bit integer.
> @@ -1342,20 +1333,21 @@ static u32 s32ton(__s32 value, unsigned n)
>   * While the USB HID spec allows unlimited length bit fields in "report
>   * descriptors", most devices never use more than 16 bits.
>   * One model of UPS is claimed to report "LINEV" as a 32-bit field.
> + * Some digitizers report stylus transducer IDs as 64-bit fields.
>   * Search linux-kernel and linux-usb-devel archives for "hid-core extract".
>   */
>
> -static u32 __extract(u8 *report, unsigned offset, int n)
> +static u64 __extract(u8 *report, unsigned offset, int n)
>  {
>   unsigned int idx = offset / 8;
>   unsigned int bit_nr = 0;
>   unsigned int bit_shift = offset % 8;
>   int bits_to_copy = 8 - bit_shift;
> - u32 value = 0;
> - u32 mask = n < 32 ? (1U << n) - 1 : ~0U;
> + u64 value = 0;
> + u64 mask = n < 64 ? (1ULL << n) - 1 : ~0ULL;
>
>   while (n > 0) {
> - value |= ((u32)report[idx] >> bit_shift) << bit_nr;
> + value |= ((u64)report[idx] >> bit_shift) << bit_nr;
>   n -= bits_to_copy;
>   bit_nr += bits_to_copy;
>   bits_to_copy = 8;
> @@ -1366,6 +1358,10 @@ static u32 __extract(u8 *report, unsigned offset, int n)
>   return value & mask;
>  }
>
> +/*
> + * Classic HID code assumes 32-bit truncation for fields. Provided
> + * for compatibility and consistency of warnings.
> + */
>  u32 hid_field_extract(const struct hid_device *hid, u8 *report,
>   unsigned offset, unsigned n)
>  {
> @@ -1379,6 +1375,22 @@ u32 hid_field_extract(const struct hid_device
> *hid, u8 *report,
>  }
>  EXPORT_SYMBOL_GPL(hid_field_extract);
>
> +/*
> + * Extract larger, 64-bit fields.
> + */
> +u64 hid_field_extract64(const struct hid_device *hid, u8 *report,
> + unsigned offset, unsigned n)
> +{
> + if (n > 64) {
> + hid_warn_once(hid, "%s() called with n (%d) > 64! (%s)\n",
> +      __func__, n, current->comm);
> + n = 64;
> + }
> +
> + return __extract(report, offset, n);
> +}
> +EXPORT_SYMBOL_GPL(hid_field_extract64);
> +
>  /*
>   * "implement" : set bits in a little endian bit stream.
>   * Same concepts as "extract" (see comments above).
> @@ -1438,7 +1450,7 @@ static void implement(const struct hid_device
> *hid, u8 *report,
>   * Search an array for a value.
>   */
>
> -static int search(__s32 *array, __s32 value, unsigned n)
> +static int search(__s64 *array, __s64 value, unsigned n)
>  {
>   while (n--) {
>   if (*array++ == value)
> @@ -1497,7 +1509,7 @@ static int hid_match_usage(struct hid_device
> *hid, struct hid_usage *usage)
>  }
>
>  static void hid_process_event(struct hid_device *hid, struct hid_field *field,
> - struct hid_usage *usage, __s32 value, int interrupt)
> + struct hid_usage *usage, __s64 value, int interrupt)
>  {
>   struct hid_driver *hdrv = hid->driver;
>   int ret;
> @@ -1506,7 +1518,7 @@ static void hid_process_event(struct hid_device
> *hid, struct hid_field *field,
>   hid_dump_input(hid, usage, value);
>
>   if (hdrv && hdrv->event && hid_match_usage(hid, usage)) {
> - ret = hdrv->event(hid, field, usage, value);
> + ret = hdrv->event(hid, field, usage, (__s32)value);
>   if (ret != 0) {
>   if (ret < 0)
>   hid_err(hid, "%s's event failed with %d\n",
> @@ -1536,18 +1548,18 @@ static void hid_input_field(struct hid_device
> *hid, struct hid_field *field,
>   unsigned size = field->report_size;
>   __s32 min = field->logical_minimum;
>   __s32 max = field->logical_maximum;
> - __s32 *value;
> + __s64 *value;
>
> - value = kmalloc_array(count, sizeof(__s32), GFP_ATOMIC);
> + value = kmalloc_array(count, sizeof(__s64), GFP_ATOMIC);
>   if (!value)
>   return;
>
>   for (n = 0; n < count; n++) {
>
>   value[n] = min < 0 ?
> - snto32(hid_field_extract(hid, data, offset + n * size,
> + sign_extend64(hid_field_extract64(hid, data, offset + n * size,
>         size), size) :
> - hid_field_extract(hid, data, offset + n * size, size);
> + hid_field_extract64(hid, data, offset + n * size, size);
>
>   /* Ignore report if ErrorRollOver */
>   if (!(field->flags & HID_MAIN_ITEM_VARIABLE) &&
> @@ -1577,7 +1589,7 @@ static void hid_input_field(struct hid_device
> *hid, struct hid_field *field,
>   hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt);
>   }
>
> - memcpy(field->value, value, count * sizeof(__s32));
> + memcpy(field->value, value, count * sizeof(__s64));
>  exit:
>   kfree(value);
>  }
> @@ -1672,7 +1684,7 @@ int hid_set_field(struct hid_field *field,
> unsigned offset, __s32 value)
>   return -1;
>   }
>   if (field->logical_minimum < 0) {
> - if (value != snto32(s32ton(value, size), size)) {
> + if (value != hid_snto32(s32ton(value, size), size)) {
>   hid_err(field->report->device, "value %d is out of range\n", value);
>   return -1;
>   }
> diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
> index 9453147d020db..badd51a8ea4ba 100644
> --- a/drivers/hid/hid-debug.c
> +++ b/drivers/hid/hid-debug.c
> @@ -692,7 +692,7 @@ void hid_dump_report(struct hid_device *hid, int
> type, u8 *data,
>  }
>  EXPORT_SYMBOL_GPL(hid_dump_report);
>
> -void hid_dump_input(struct hid_device *hdev, struct hid_usage *usage,
> __s32 value)
> +void hid_dump_input(struct hid_device *hdev, struct hid_usage *usage,
> __s64 value)
>  {
>   char *buf;
>   int len;
> @@ -701,7 +701,7 @@ void hid_dump_input(struct hid_device *hdev,
> struct hid_usage *usage, __s32 valu
>   if (!buf)
>   return;
>   len = strlen(buf);
> - snprintf(buf + len, HID_DEBUG_BUFSIZE - len - 1, " = %d\n", value);
> + snprintf(buf + len, HID_DEBUG_BUFSIZE - len - 1, " = %lld\n", value);
>
>   hid_debug_event(hdev, buf);
>
> diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
> index bceccd75b488e..87ade0d6963cf 100644
> --- a/drivers/hid/hid-input.c
> +++ b/drivers/hid/hid-input.c
> @@ -52,6 +52,7 @@ static const struct {
>  #define map_rel(c) hid_map_usage(hidinput, usage, &bit, &max, EV_REL, (c))
>  #define map_key(c) hid_map_usage(hidinput, usage, &bit, &max, EV_KEY, (c))
>  #define map_led(c) hid_map_usage(hidinput, usage, &bit, &max, EV_LED, (c))
> +#define map_msc(c) hid_map_usage(hidinput, usage, &bit, &max, EV_MSC, (c))
>
>  #define map_abs_clear(c) hid_map_usage_clear(hidinput, usage, &bit, \
>   &max, EV_ABS, (c))
> @@ -286,6 +287,7 @@ static enum power_supply_property
> hidinput_battery_props[] = {
>   POWER_SUPPLY_PROP_ONLINE,
>   POWER_SUPPLY_PROP_CAPACITY,
>   POWER_SUPPLY_PROP_MODEL_NAME,
> + POWER_SUPPLY_PROP_SERIAL_NUMBER,
>   POWER_SUPPLY_PROP_STATUS,
>   POWER_SUPPLY_PROP_SCOPE,
>  };
> @@ -402,6 +404,22 @@ static int hidinput_get_battery_property(struct
> power_supply *psy,
>   val->strval = dev->name;
>   break;
>
> + case POWER_SUPPLY_PROP_SERIAL_NUMBER:
> + /* Serial number does not have an active HID query
> + * mechanism like hidinput_query_battery_capacity, as the
> + * only devices expected to have serial numbers are digitizers,
> + * which are unlikely to be able to pull the serial number from
> + * an untethered pen on demand.
> + */
> + if (dev->battery_serial_number == 0) {
> + /* Make no claims about S/N format if we haven't actually seen a value yet. */
> + strcpy(dev->battery_serial_number_str, "");
> + } else {
> + snprintf(dev->battery_serial_number_str,
> sizeof(dev->battery_serial_number_str), "DG:%0*llX",
> (dev->battery_serial_number_bits+3)/4, dev->battery_serial_number);
> + }
> + val->strval = dev->battery_serial_number_str;
> + break;
> +
>   case POWER_SUPPLY_PROP_STATUS:
>   if (dev->battery_status != HID_BATTERY_REPORTED &&
>      !dev->battery_avoid_query) {
> @@ -485,6 +503,8 @@ static int hidinput_setup_battery(struct
> hid_device *dev, unsigned report_type,
>   dev->battery_max = max;
>   dev->battery_report_type = report_type;
>   dev->battery_report_id = field->report->id;
> + dev->battery_changed = false;
> + dev->battery_reported = false;
>
>   /*
>   * Stylus is normally not connected to the device and thus we
> @@ -526,7 +546,7 @@ static void hidinput_cleanup_battery(struct hid_device *dev)
>   dev->battery = NULL;
>  }
>
> -static void hidinput_update_battery(struct hid_device *dev, int value)
> +static void hidinput_update_battery_capacity(struct hid_device *dev,
> __s32 value)
>  {
>   int capacity;
>
> @@ -538,11 +558,47 @@ static void hidinput_update_battery(struct
> hid_device *dev, int value)
>
>   capacity = hidinput_scale_battery_capacity(dev, value);
>
> + if (capacity != dev->battery_capacity) {
> + dev->battery_capacity = capacity;
> + dev->battery_changed = true;
> + }
> + dev->battery_reported = true;
> +}
> +
> +static void hidinput_update_battery_serial(struct hid_device *dev,
> __u64 value, int bits)
> +{
> + if (!dev->battery)
> + return;
> +
> + if (value == 0)
> + return;
> +
> + if (value != dev->battery_serial_number) {
> + dev->battery_serial_number = value;
> + dev->battery_serial_number_bits = bits;
> + dev->battery_changed = true;
> + }
> + dev->battery_reported = true;
> +}
> +
> +static void hidinput_flush_battery(struct hid_device *dev)
> +{
> + if (!dev->battery)
> + return;
> +
> + /* Only consider pushing a battery change if there is a
> + * battery field in this report.
> + */
> + if (!dev->battery_reported)
> + return;
> +
> + dev->battery_reported = false;
> +
>   if (dev->battery_status != HID_BATTERY_REPORTED ||
> -    capacity != dev->battery_capacity ||
> + dev->battery_changed ||
>      ktime_after(ktime_get_coarse(), dev->battery_ratelimit_time)) {
> - dev->battery_capacity = capacity;
>   dev->battery_status = HID_BATTERY_REPORTED;
> + dev->battery_changed = false;
>   dev->battery_ratelimit_time =
>   ktime_add_ms(ktime_get_coarse(), 30 * 1000);
>   power_supply_changed(dev->battery);
> @@ -559,7 +615,15 @@ static void hidinput_cleanup_battery(struct
> hid_device *dev)
>  {
>  }
>
> -static void hidinput_update_battery(struct hid_device *dev, int value)
> +static void hidinput_update_battery_capacity(struct hid_device *dev,
> __s32 value)
> +{
> +}
> +
> +static void hidinput_update_battery_serial(struct hid_device *dev,
> __u64 value, int bits)
> +{
> +}
> +
> +static void hidinput_flush_battery(struct hid_device *dev)
>  {
>  }
>  #endif /* CONFIG_HID_BATTERY_STRENGTH */
> @@ -850,6 +914,13 @@ static void hidinput_configure_usage(struct
> hid_input *hidinput, struct hid_fiel
>   usage->code = MSC_SERIAL;
>   bit = input->mscbit;
>   max = MSC_MAX;
> + if (field->report_size > 32) {
> + /* Deliver up to 64 bits of TransducerSerialNumber via
> + * MSC_SERIAL and MSC_SERIAL2.
> + */
> + set_bit(MSC_SERIAL2, input->mscbit);
> + set_bit(EV_MSC, input->evbit);
> + }
>   break;
>
>   default:  goto unknown;
> @@ -1243,7 +1314,7 @@ static void hidinput_configure_usage(struct
> hid_input *hidinput, struct hid_fiel
>
>  static void hidinput_handle_scroll(struct hid_usage *usage,
>     struct input_dev *input,
> -   __s32 value)
> +   __s64 value)
>  {
>   int code;
>   int hi_res, lo_res;
> @@ -1273,8 +1344,9 @@ static void hidinput_handle_scroll(struct
> hid_usage *usage,
>   input_event(input, EV_REL, usage->code, hi_res);
>  }
>
> -void hidinput_hid_event(struct hid_device *hid, struct hid_field
> *field, struct hid_usage *usage, __s32 value)
> +void hidinput_hid_event(struct hid_device *hid, struct hid_field
> *field, struct hid_usage *usage, __s64 value64)
>  {
> + __s32 value = value64;
>   struct input_dev *input;
>   unsigned *quirks = &hid->quirks;
>
> @@ -1282,15 +1354,28 @@ void hidinput_hid_event(struct hid_device
> *hid, struct hid_field *field, struct
>   return;
>
>   if (usage->type == EV_PWR) {
> - hidinput_update_battery(hid, value);
> + hidinput_update_battery_capacity(hid, value);
>   return;
>   }
> + if (usage->type == EV_MSC && usage->code == MSC_SERIAL) {
> + hidinput_update_battery_serial(hid, value64, field->report_size);
> + }
>
>   if (!field->hidinput)
>   return;
>
>   input = field->hidinput->input;
>
> + if (usage->type == EV_MSC && usage->code == MSC_SERIAL &&
> field->report_size > 32) {
> + /* min/max are limited to 32-bits by spec and cannot be relevant if field is
> + * this large, ignore them and send 64 bits through. We leave fields <= 32 bits
> + * to be processed later with normal clamping, for compatibility.
> + */
> + input_event(input, usage->type, MSC_SERIAL, (__u32)value64);
> + input_event(input, usage->type, MSC_SERIAL2, value64 >> 32);
> + return;
> + }
> +
>   if (usage->hat_min < usage->hat_max || usage->hat_dir) {
>   int hat_dir = usage->hat_dir;
>   if (!hat_dir)
> @@ -1415,6 +1500,8 @@ void hidinput_report_event(struct hid_device
> *hid, struct hid_report *report)
>  {
>   struct hid_input *hidinput;
>
> + hidinput_flush_battery(hid);
> +
>   if (hid->quirks & HID_QUIRK_NO_INPUT_SYNC)
>   return;
>
> diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
> index d91e6679afb18..23868a2e31187 100644
> --- a/drivers/hid/hid-multitouch.c
> +++ b/drivers/hid/hid-multitouch.c
> @@ -95,11 +95,11 @@ static const __s32 mzero; /* default for 0 */
>
>  struct mt_usages {
>   struct list_head list;
> - __s32 *x, *y, *cx, *cy, *p, *w, *h, *a;
> - __s32 *contactid; /* the device ContactID assigned to this slot */
> - bool *tip_state; /* is the touch valid? */
> - bool *inrange_state; /* is the finger in proximity of the sensor? */
> - bool *confidence_state; /* is the touch made by a finger? */
> + __s64 *x, *y, *cx, *cy, *p, *w, *h, *a;
> + __s64 *contactid; /* the device ContactID assigned to this slot */
> + __s64 *tip_state; /* is the touch valid? */
> + __s64 *inrange_state; /* is the finger in proximity of the sensor? */
> + __s64 *confidence_state; /* is the touch made by a finger? */
>  };
>
>  struct mt_application {
> @@ -110,10 +110,10 @@ struct mt_application {
>
>   __s32 quirks;
>
> - __s32 *scantime; /* scantime reported */
> + __s64 *scantime; /* scantime reported */
>   __s32 scantime_logical_max; /* max value for raw scantime */
>
> - __s32 *raw_cc; /* contact count in the report */
> + __s64 *raw_cc; /* contact count in the report */
>   int left_button_state; /* left button state */
>   unsigned int mt_flags; /* flags to pass to input-mt */
>
> @@ -642,11 +642,11 @@ static struct mt_report_data
> *mt_find_report_data(struct mt_device *td,
>
>  static void mt_store_field(struct hid_device *hdev,
>     struct mt_application *application,
> -   __s32 *value,
> +   __s64 *value,
>     size_t offset)
>  {
>   struct mt_usages *usage;
> - __s32 **target;
> + __s64 **target;
>
>   if (list_empty(&application->mt_usages))
>   usage = mt_allocate_usage(hdev, application);
> @@ -658,7 +658,7 @@ static void mt_store_field(struct hid_device *hdev,
>   if (!usage)
>   return;
>
> - target = (__s32 **)((char *)usage + offset);
> + target = (__s64 **)((char *)usage + offset);
>
>   /* the value has already been filled, create a new slot */
>   if (*target != DEFAULT_TRUE &&
> @@ -675,7 +675,7 @@ static void mt_store_field(struct hid_device *hdev,
>   if (!usage)
>   return;
>
> - target = (__s32 **)((char *)usage + offset);
> + target = (__s64 **)((char *)usage + offset);
>   }
>
>   *target = value;
> diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
> index 2f073f5360706..6501f33dbc725 100644
> --- a/drivers/hid/hid-sony.c
> +++ b/drivers/hid/hid-sony.c
> @@ -1827,7 +1827,7 @@ static void buzz_set_leds(struct sony_sc *sc)
>   &hdev->report_enum[HID_OUTPUT_REPORT].report_list;
>   struct hid_report *report = list_entry(report_list->next,
>   struct hid_report, list);
> - s32 *value = report->field[0]->value;
> + s64 *value = report->field[0]->value;
>
>   BUILD_BUG_ON(MAX_LEDS < 4);
>
> diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
> index fddac7c72f645..a8fb81cccb981 100644
> --- a/drivers/hid/usbhid/hid-pidff.c
> +++ b/drivers/hid/usbhid/hid-pidff.c
> @@ -138,7 +138,7 @@ static const u8 pidff_effect_operation_status[] =
> { 0x79, 0x7b };
>
>  struct pidff_usage {
>   struct hid_field *field;
> - s32 *value;
> + s64 *value;
>  };
>
>  struct pidff_device {
> diff --git a/include/linux/hid-debug.h b/include/linux/hid-debug.h
> index ea7b23d13bfdf..280de6b7904e7 100644
> --- a/include/linux/hid-debug.h
> +++ b/include/linux/hid-debug.h
> @@ -16,7 +16,7 @@
>  #define HID_DEBUG_BUFSIZE 512
>  #define HID_DEBUG_FIFOSIZE 512
>
> -void hid_dump_input(struct hid_device *, struct hid_usage *, __s32);
> +void hid_dump_input(struct hid_device *, struct hid_usage *, __s64);
>  void hid_dump_report(struct hid_device *, int , u8 *, int);
>  void hid_dump_device(struct hid_device *, struct seq_file *);
>  void hid_dump_field(struct hid_field *, int, struct seq_file *);
> diff --git a/include/linux/hid.h b/include/linux/hid.h
> index 58e635bf4ed09..f0520417a91d5 100644
> --- a/include/linux/hid.h
> +++ b/include/linux/hid.h
> @@ -389,6 +389,7 @@ struct hid_item {
>
>  struct hid_global {
>   unsigned usage_page;
> + /* HID Global fields are constrained by spec to 32-bits */
>   __s32    logical_minimum;
>   __s32    logical_maximum;
>   __s32    physical_minimum;
> @@ -458,7 +459,7 @@ struct hid_field {
>   unsigned  report_size; /* size of this field in the report */
>   unsigned  report_count; /* number of this field in the report */
>   unsigned  report_type; /* (input,output,feature) */
> - __s32    *value; /* last known value(s) */
> + __s64    *value; /* last known value(s); 64-bit values are the
> largest we process */
>   __s32     logical_minimum;
>   __s32     logical_maximum;
>   __s32     physical_minimum;
> @@ -584,8 +585,13 @@ struct hid_device { /* device report descriptor */
>   __s32 battery_max;
>   __s32 battery_report_type;
>   __s32 battery_report_id;
> + __u64 battery_serial_number;
> + int battery_serial_number_bits; /* Actual number of digits in SN */
> + char battery_serial_number_str[20]; /* Space for "DG:" + max 16 hex digits */
>   enum hid_battery_status battery_status;
>   bool battery_avoid_query;
> + bool battery_changed;
> + bool battery_reported;
>   ktime_t battery_ratelimit_time;
>  #endif
>
> @@ -875,7 +881,7 @@ extern void hid_unregister_driver(struct hid_driver *);
>   module_driver(__hid_driver, hid_register_driver, \
>        hid_unregister_driver)
>
> -extern void hidinput_hid_event(struct hid_device *, struct hid_field
> *, struct hid_usage *, __s32);
> +extern void hidinput_hid_event(struct hid_device *, struct hid_field
> *, struct hid_usage *, __s64);
>  extern void hidinput_report_event(struct hid_device *hid, struct
> hid_report *report);
>  extern int hidinput_connect(struct hid_device *hid, unsigned int force);
>  extern void hidinput_disconnect(struct hid_device *);
> @@ -913,8 +919,11 @@ const struct hid_device_id
> *hid_match_device(struct hid_device *hdev,
>  bool hid_compare_device_paths(struct hid_device *hdev_a,
>        struct hid_device *hdev_b, char separator);
>  s32 hid_snto32(__u32 value, unsigned n);
> +s64 hid_snto64(__u64 value, unsigned n);
>  __u32 hid_field_extract(const struct hid_device *hid, __u8 *report,
>       unsigned offset, unsigned n);
> +__u64 hid_field_extract64(const struct hid_device *hid, __u8 *report,
> +     unsigned offset, unsigned n);
>
>  /**
>   * hid_device_io_start - enable HID input during probe, remove
> diff --git a/include/uapi/linux/input-event-codes.h
> b/include/uapi/linux/input-event-codes.h
> index 472cd5bc55676..612ca91a87326 100644
> --- a/include/uapi/linux/input-event-codes.h
> +++ b/include/uapi/linux/input-event-codes.h
> @@ -816,12 +816,13 @@
>   * Misc events
>   */
>
> -#define MSC_SERIAL 0x00
> +#define MSC_SERIAL 0x00 /* First 32-bits of serial number */
>  #define MSC_PULSELED 0x01
>  #define MSC_GESTURE 0x02
>  #define MSC_RAW 0x03
>  #define MSC_SCAN 0x04
>  #define MSC_TIMESTAMP 0x05
> +#define MSC_SERIAL2 0x06 /* Second 32-bits of serial number */
>  #define MSC_MAX 0x07
>  #define MSC_CNT (MSC_MAX+1)
>
> --
> 2.29.2
>


  reply	other threads:[~2021-03-25  8:36 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-24 19:53 Supporting 64-bit Digitizer Serial Numbers? Kenneth Albanowski
2021-03-25  8:35 ` Benjamin Tissoires [this message]
2021-03-26  5:56   ` Peter Hutterer
2021-03-31 19:59   ` Kenneth Albanowski
2021-04-08 22:19     ` Gerecke, Jason
2021-04-08 23:32       ` Kenneth Albanowski

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAO-hwJ+6g9ADRpShG_HbQi5PGv6PLp-1wxJP7CSLT+1uJLB9OA@mail.gmail.com \
    --to=benjamin.tissoires@redhat.com \
    --cc=Jason.Gerecke@wacom.com \
    --cc=dmitry.torokhov@gmail.com \
    --cc=jikos@kernel.org \
    --cc=kenalba@google.com \
    --cc=linux-input@vger.kernel.org \
    --cc=peter.hutterer@who-t.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.