All of lore.kernel.org
 help / color / mirror / Atom feed
* [Patch] HID: non-overlapping zeroing of extra bits
@ 2010-04-12 18:16 Pete Zaitcev
  2010-04-13 13:56 ` Jiri Kosina
  0 siblings, 1 reply; 2+ messages in thread
From: Pete Zaitcev @ 2010-04-12 18:16 UTC (permalink / raw)
  To: Jiri Kosina; +Cc: linux-input, zaitcev

>From my review of the way the unused bits of report are being zeroed,
it seems like there must be a bug. Currently, the zeroing is done
in hid_output_field and it covers any bits between the last used bit
and the end of the byte. But in case of, say, my keyboard, NumLock is
mask 0x01 and CapsLock is 0x02. Invoking hid_output_field for NumLock
definitely zeroes across CapsLock. The only reason this works is that
the fields are sorted by the offset.

It would be more correct and simpler to zero-fill the buffer into
which the fields are set.

The patch is tested with an IBM keyboard that is improperly sensitive
to out-of-report pad bits, the extra bits are still zeroed and the
fields continue to work as expected. It is also tested with good
keyboards.

In case, a related bug in RHEL 5 is tracked with Red Hat bug 513934.

Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>

diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -940,13 +940,8 @@ static void hid_output_field(struct hid_field *field, __u8 *data)
 	unsigned count = field->report_count;
 	unsigned offset = field->report_offset;
 	unsigned size = field->report_size;
-	unsigned bitsused = offset + count * size;
 	unsigned n;
 
-	/* make sure the unused bits in the last byte are zeros */
-	if (count > 0 && size > 0 && (bitsused % 8) != 0)
-		data[(bitsused-1)/8] &= (1 << (bitsused % 8)) - 1;
-
 	for (n = 0; n < count; n++) {
 		if (field->logical_minimum < 0)	/* signed values */
 			implement(data, offset + n * size, size, s32ton(field->value[n], size));
@@ -966,6 +961,7 @@ void hid_output_report(struct hid_report *report, __u8 *data)
 	if (report->id > 0)
 		*data++ = report->id;
 
+	memset(data, 0, ((report->size - 1) >> 3) + 1);
 	for (n = 0; n < report->maxfield; n++)
 		hid_output_field(report->field[n], data);
 }

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [Patch] HID: non-overlapping zeroing of extra bits
  2010-04-12 18:16 [Patch] HID: non-overlapping zeroing of extra bits Pete Zaitcev
@ 2010-04-13 13:56 ` Jiri Kosina
  0 siblings, 0 replies; 2+ messages in thread
From: Jiri Kosina @ 2010-04-13 13:56 UTC (permalink / raw)
  To: Pete Zaitcev; +Cc: linux-input

On Mon, 12 Apr 2010, Pete Zaitcev wrote:

> From my review of the way the unused bits of report are being zeroed,
> it seems like there must be a bug. Currently, the zeroing is done
> in hid_output_field and it covers any bits between the last used bit
> and the end of the byte. But in case of, say, my keyboard, NumLock is
> mask 0x01 and CapsLock is 0x02. Invoking hid_output_field for NumLock
> definitely zeroes across CapsLock. The only reason this works is that
> the fields are sorted by the offset.
> 
> It would be more correct and simpler to zero-fill the buffer into
> which the fields are set.
> 
> The patch is tested with an IBM keyboard that is improperly sensitive
> to out-of-report pad bits, the extra bits are still zeroed and the
> fields continue to work as expected. It is also tested with good
> keyboards.
> 
> In case, a related bug in RHEL 5 is tracked with Red Hat bug 513934.
> 
> Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
> 
> diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
> --- a/drivers/hid/hid-core.c
> +++ b/drivers/hid/hid-core.c
> @@ -940,13 +940,8 @@ static void hid_output_field(struct hid_field *field, __u8 *data)
>  	unsigned count = field->report_count;
>  	unsigned offset = field->report_offset;
>  	unsigned size = field->report_size;
> -	unsigned bitsused = offset + count * size;
>  	unsigned n;
>  
> -	/* make sure the unused bits in the last byte are zeros */
> -	if (count > 0 && size > 0 && (bitsused % 8) != 0)
> -		data[(bitsused-1)/8] &= (1 << (bitsused % 8)) - 1;
> -
>  	for (n = 0; n < count; n++) {
>  		if (field->logical_minimum < 0)	/* signed values */
>  			implement(data, offset + n * size, size, s32ton(field->value[n], size));
> @@ -966,6 +961,7 @@ void hid_output_report(struct hid_report *report, __u8 *data)
>  	if (report->id > 0)
>  		*data++ = report->id;
>  
> +	memset(data, 0, ((report->size - 1) >> 3) + 1);
>  	for (n = 0; n < report->maxfield; n++)
>  		hid_output_field(report->field[n], data);
>  }

I have applied the patch, thanks Pete.

-- 
Jiri Kosina
SUSE Labs, Novell Inc.

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2010-04-13 13:56 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-04-12 18:16 [Patch] HID: non-overlapping zeroing of extra bits Pete Zaitcev
2010-04-13 13:56 ` Jiri Kosina

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.