From b.candler@pobox.com  Sat Feb 21 06:35:31 2004
Return-Path: <b.candler@pobox.com>
Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125])
	by hub.freebsd.org (Postfix) with ESMTP id C260E16A4CE
	for <FreeBSD-gnats-submit@freebsd.org>; Sat, 21 Feb 2004 06:35:31 -0800 (PST)
Received: from mk-smarthost-3.mail.uk.tiscali.com (mk-smarthost-3.mail.uk.tiscali.com [212.74.114.39])
	by mx1.FreeBSD.org (Postfix) with ESMTP id 7086D43D1D
	for <FreeBSD-gnats-submit@freebsd.org>; Sat, 21 Feb 2004 06:35:31 -0800 (PST)
	(envelope-from b.candler@pobox.com)
Received: from ppp-1-179.lond-a-1.access.uk.tiscali.com ([80.225.197.179]:2051 helo=vaio.linnet.org)
	by mk-smarthost-3.mail.uk.tiscali.com with esmtp (Exim 4.24)
	id 1AuYE4-000NDe-9h
	for FreeBSD-gnats-submit@freebsd.org; Sat, 21 Feb 2004 14:35:28 +0000
Received: from brian by vaio.linnet.org with local (Exim 4.30)
	id 1AuYE3-00006b-3x
	for FreeBSD-gnats-submit@freebsd.org; Sat, 21 Feb 2004 14:35:27 +0000
Message-Id: <E1AuYE3-00006b-3x@vaio.linnet.org>
Date: Sat, 21 Feb 2004 14:35:27 +0000
From: Brian Candler <B.Candler@pobox.com>
Reply-To: Brian Candler <B.Candler@pobox.com>
To: FreeBSD-gnats-submit@freebsd.org
Cc:
Subject: USB keyboard rollover error [ukbd.c patch]
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         63171
>Category:       kern
>Synopsis:       USB keyboard rollover error [ukbd.c patch]
>Confidential:   no
>Severity:       serious
>Priority:       low
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sat Feb 21 06:40:14 PST 2004
>Closed-Date:    Mon Feb 23 07:37:15 PST 2004
>Last-Modified:  Mon Feb 23 09:30:03 PST 2004
>Originator:     Brian Candler
>Release:        FreeBSD 4.8-RELEASE i386
>Organization:
>Environment:
System: 4.8-RELEASE FreeBSD 4.8-RELEASE #5: Sat Feb 21 13:49:32 GMT 2004 root@vaio.linnet.org:/usr/src/sys/compile/VAIO i386
Sony Vaio PCG-C1F
USB Keyboard (Packard Bell PB-KB400)

	
>Description:
N-key rollover fails to work properly with a USB keyboard, giving duplicate
characters.

Thisi is a prorbleme when youo a rer typing veryr quiuckcly!

A second, unrelated issue is that there is a wrong pointer type being passed
to usbd_set_polling, which manifests itself as a compiler warning but could
cause memory corruption. The attached patch corrects both problems.

>How-To-Repeat:
	
Plug in a USB keyboard. Activate it using

#!/bin/sh
kbdcontrol -k /dev/kbd1 </dev/console
kbdcontrol -l /usr/share/syscons/keymaps/uk.cp850.kbd # optional
kbdcontrol -r slow    # makes it easier to demonstrate the problem

Perform the following operations:

Press "a", press "s", release "a", press "d"

The sequence "asds" (instead of "asd") is printed. If you keep "s" held and
keep releasing and pressing "d", you will get "ds" printed each time you
press "d".

If you enable USB debugging in the kernel, and set
# sysctl -w hw.usb.ukbd.debug=1
then you get

Feb 20 15:21:21 vaio /kernel: 0x428 (1064) released
Feb 20 15:21:21 vaio /kernel: 
Feb 20 15:21:26 vaio /kernel: 0x4 (4) pressed                 <<< a
Feb 20 15:21:26 vaio /kernel: 4 
Feb 20 15:21:26 vaio /kernel: 0x16 (22) pressed               <<< s
Feb 20 15:21:26 vaio /kernel: 4 22 
Feb 20 15:21:26 vaio /kernel: 0x404 (1028) released
Feb 20 15:21:26 vaio /kernel: 0x416 (1046) released
Feb 20 15:21:26 vaio /kernel: 22 
Feb 20 15:21:26 vaio /kernel: 0x7 (7) pressed                 <<< d
Feb 20 15:21:26 vaio /kernel: 0x16 (22) pressed               <<< s
Feb 20 15:21:26 vaio /kernel: 7 22 
Feb 20 15:21:26 vaio /kernel: 0x416 (1046) released
Feb 20 15:21:26 vaio /kernel: 7 
Feb 20 15:21:27 vaio /kernel: 0x407 (1031) released
Feb 20 15:21:27 vaio /kernel: 

This is even after updating my ukbd.c to the latest in CVS (rev 1.46).

>Fix:

The keyboard driver keeps a list of keys held (ks_ndata and ks_odata) and
looks for differences between them to identify key presses and releases.
However it makes the erroneous assumption that the first zero entry seen
indicates the end of the list. In fact, when you press the key sequence
above, you get

(1) _ _ _ _ _ _		Initial empty list
(2) a _ _ _ _ _		"a" pressed
(3) a s _ _ _ _		"s" pressed
(4) _ s _ _ _ _		"a" released
(5) d s _ _ _ _		"d" pressed

At least this is true with my USB keyboard; I haven't checked the HID spec,
but given that my keyboard works correctly under Windows98 with no rollover
problems I think it is entitled to behave in this way. The fix is very
straightforward, changing 'break' to 'continue' in a few places.

The pointer error looks like an oversight, and the last part of the patch
makes what seems to be the obvious correction, although I am not intimate
with the USB data structures so this ought to be checked by someone who is.
(usbd_set_polling requires a usbd_interface_handle, not a
usbd_device_handle, as its first parameter).

Regards,

Brian Candler.

--- sys/dev/usb/ukbd.c-1.46	Sat Feb 21 12:17:38 2004
+++ sys/dev/usb/ukbd.c	Sat Feb 21 13:47:56 2004
@@ -43,7 +43,7 @@
 __FBSDID("$FreeBSD: /repoman/r/ncvs/src/sys/dev/usb/ukbd.c,v 1.46 2004/01/03 15:01:04 sanpei Exp $");
 
 /*
- * HID spec: http://www.usb.org/developers/data/devclass/hid1_1.pdf
+ * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
  */
 
 #include "opt_kbd.h"
@@ -746,10 +746,10 @@
 	for (i = 0; i < NKEYCODE; i++) {
 		key = state->ks_odata.keycode[i];
 		if (key == 0)
-			break;
+			continue;
 		for (j = 0; j < NKEYCODE; j++) {
 			if (ud->keycode[j] == 0)
-				break;
+				continue;
 			if (key == ud->keycode[j])
 				goto rfound;
 		}
@@ -762,11 +762,11 @@
 	for (i = 0; i < NKEYCODE; i++) {
 		key = ud->keycode[i];
 		if (key == 0)
-			break;
+			continue;
 		state->ks_ntime[i] = now + kbd->kb_delay1;
 		for (j = 0; j < NKEYCODE; j++) {
 			if (state->ks_odata.keycode[j] == 0)
-				break;
+				continue;
 			if (key == state->ks_odata.keycode[j]) {
 				state->ks_ntime[i] = state->ks_otime[j];
 				if (state->ks_otime[j] > now)
@@ -1327,21 +1327,19 @@
 ukbd_poll(keyboard_t *kbd, int on)
 {
 	ukbd_state_t *state;
-	usbd_device_handle dev;
 	int s;
 
 	state = (ukbd_state_t *)kbd->kb_data;
-	usbd_interface2device_handle(state->ks_iface, &dev);
 
 	s = splusb();
 	if (on) {
 		if (state->ks_polling == 0)
-			usbd_set_polling(dev, on);
+			usbd_set_polling(state->ks_iface, on);
 		++state->ks_polling;
 	} else {
 		--state->ks_polling;
 		if (state->ks_polling == 0)
-			usbd_set_polling(dev, on);
+			usbd_set_polling(state->ks_iface, on);
 	}
 	splx(s);
 	return 0;
>Release-Note:
>Audit-Trail:

From: Brian Candler <B.Candler@pobox.com>
To: FreeBSD-gnats-submit@FreeBSD.org, freebsd-bugs@FreeBSD.org
Cc:  
Subject: Re: kern/63171: USB keyboard rollover error [ukbd.c patch]
Date: Sat, 21 Feb 2004 14:47:53 +0000

 Turns out this is a superset of kern/57273 posted last September. My patch
 also fixes the pointer bug.
 
 Can someone commit please?
 
 Thanks,
 
 Brian.
State-Changed-From-To: open->closed 
State-Changed-By: jhb 
State-Changed-When: Mon Feb 23 07:36:50 PST 2004 
State-Changed-Why:  
Duplicate of 57273. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=63171 

From: John Baldwin <john@baldwin.cx>
To: freebsd-gnats-submit@FreeBSD.org, B.Candler@pobox.com
Cc:  
Subject: Re: kern/63171: USB keyboard rollover error [ukbd.c patch]
Date: Mon, 23 Feb 2004 10:34:08 -0500

 The pointer fix does not seem correct.  usbd_set_polling() does take a 
 usbd_device_handle, not an interface pointer, so the existing code is correct 
 on -current at least.  Note that on 4.x, the poll method in ukbd.c does not 
 use usbd_device_handle's but does pass the iface pointer in.  This is due to 
 the usbd code being different in current and stable.  I have committed the 
 ukbd rollover fix however.
 
 -- 
 John Baldwin <john@baldwin.cx>  <><  http://www.baldwin.cx/~john/
 "Power Users Use the Power to Serve"  =  http://www.FreeBSD.org

From: Brian Candler <B.Candler@pobox.com>
To: John Baldwin <john@baldwin.cx>
Cc: freebsd-gnats-submit@FreeBSD.org
Subject: Re: kern/63171: USB keyboard rollover error [ukbd.c patch]
Date: Mon, 23 Feb 2004 17:21:23 +0000

 On Mon, Feb 23, 2004 at 10:34:08AM -0500, John Baldwin wrote:
 > The pointer fix does not seem correct.  usbd_set_polling() does take a 
 > usbd_device_handle, not an interface pointer, so the existing code is correct 
 > on -current at least.  Note that on 4.x, the poll method in ukbd.c does not 
 > use usbd_device_handle's but does pass the iface pointer in.  This is due to 
 > the usbd code being different in current and stable.
 
 Ah, this is probably because I updated ukbd.c to a newer version in an
 attempt to see if the problem had already been fixed.
 
 Until I changed it, gcc was giving an "incompatible pointer type" warning in
 two places when ukbd.c was compiled.
 
 In my usbdi.c [1.60] I have:
 
 usbd_set_polling(usbd_interface_handle iface, int on)
 
 But I see that the CVS head [1.84] has usbd_device_handle instead. So you're
 quite right, and sorry for the noise.
 
 > I have committed the ukbd rollover fix however.
 
 Thank you!
 
 Brian.
>Unformatted:
