Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 3797

kernel-2.6.18-194.11.1.el5.src.rpm

From: Pete Zaitcev <zaitcev@redhat.com>
Date: Thu, 6 Dec 2007 15:33:39 -0800
Subject: [usb] reset LEDs on Dell keyboards
Message-id: 20071206153339.a55fb831.zaitcev@redhat.com
O-Subject: Re: [RHEL5 U2] bz#228674 Reset LEDs on Dell keyboards
Bugzilla: 228674

This will be the easiest patch to ack. It is very safe because it only
activates for specific hardware, and it is upstream. I've built a test
kernel for Dell, it worked. I also re-verified that the patch still
applies to the today's RHEL-5 tip (2.6.18-54.el5).

Now, for the record, the issue is that if BIOS leaves NumLock on, on
some keyboards a USB reset does not clear it. At first I tried to be
too clever and get the current state from BIOS memory area, then
persuade the input layer to start with nonzero shift state. It turned
out to be much more difficult than it looked, for very marginal
benefit. So, the patch "simply" makes sure that a USB reset clears
LEDs and thus avoids patching half of the drivers/input.

BTW, this is a reminder how useful blacklists are. If we created a
generic solution which tracked BIOS's shift state, we'd end with a pile
of fragile code which we could never remove. But all this stuff will
be gone in a few years, when incorrently working keyboards get retired.

Please ACK.

-- Pete

diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
index e8038f8..73a9310 100644
--- a/drivers/usb/input/hid-core.c
+++ b/drivers/usb/input/hid-core.c
@@ -1411,6 +1411,45 @@ void hid_init_reports(struct hid_device *hid)
 		warn("timeout initializing reports");
 }
 
+/*
+ * Reset LEDs which BIOS might have left on. For now, just NumLock (0x01).
+ */
+
+static int hid_find_field_early(struct hid_device *hid, unsigned int page,
+    unsigned int hid_code, struct hid_field **pfield)
+{
+	struct hid_report *report;
+	struct hid_field *field;
+	struct hid_usage *usage;
+	int i, j;
+
+	list_for_each_entry(report, &hid->report_enum[HID_OUTPUT_REPORT].report_list, list) {
+		for (i = 0; i < report->maxfield; i++) {
+			field = report->field[i];
+			for (j = 0; j < field->maxusage; j++) {
+				usage = &field->usage[j];
+				if ((usage->hid & HID_USAGE_PAGE) == page &&
+				    (usage->hid & 0xFFFF) == hid_code) {
+					*pfield = field;
+					return j;
+				}
+			}
+		}
+	}
+	return -1;
+}
+
+static void hid_set_leds(struct hid_device *hid)
+{
+	struct hid_field *field;
+	int offset;
+
+	if ((offset = hid_find_field_early(hid, HID_UP_LED, 0x01, &field)) != -1) {
+		hid_set_field(field, offset, 0);
+		hid_submit_report(hid, field->report, USB_DIR_OUT);
+	}
+}
+
 #define USB_VENDOR_ID_GTCO		0x078c
 #define USB_DEVICE_ID_GTCO_90		0x0090
 #define USB_DEVICE_ID_GTCO_100		0x0100
@@ -1594,6 +1633,9 @@ void hid_init_reports(struct hid_device *hid)
 #define USB_VENDOR_ID_SUN		0x0430
 #define USB_DEVICE_ID_RARITAN_KVM_DONGLE	0xcdab
 
+#define USB_VENDOR_ID_DELL		0x413c
+#define USB_DEVICE_ID_DELL_W7658	0x2005
+
 /*
  * Alphabetically sorted blacklist by quirk type.
  */
@@ -1752,6 +1794,8 @@ static const struct hid_blacklist {
 	{ USB_VENDOR_ID_PANJIT, 0x0003, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_PANJIT, 0x0004, HID_QUIRK_IGNORE },
 
+	{ USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658, HID_QUIRK_RESET_LEDS },
+
 	{ 0, 0 }
 };
 
@@ -2065,6 +2109,8 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
 
 	hid_init_reports(hid);
 	hid_dump_device(hid);
+	if (hid->quirks & HID_QUIRK_RESET_LEDS)
+		hid_set_leds(hid);
 
 	if (!hidinput_connect(hid))
 		hid->claimed |= HID_CLAIMED_INPUT;
diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h
index aa85d0b..928d8a3 100644
--- a/drivers/usb/input/hid.h
+++ b/drivers/usb/input/hid.h
@@ -261,6 +261,7 @@ struct hid_item {
 #define HID_QUIRK_POWERBOOK_FN_ON		0x00002000
 #define HID_QUIRK_INVERT_HWHEEL			0x00004000
 #define HID_QUIRK_POWERBOOK_ISO_KEYBOARD	0x00010000
+#define HID_QUIRK_RESET_LEDS			0x00400000
 
 /*
  * This is the global environment of the parser. This information is