LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* Kernel panic (networking-related?)
@ 2008-03-09 14:24 Darren Salt
  0 siblings, 0 replies; only message in thread
From: Darren Salt @ 2008-03-09 14:24 UTC (permalink / raw)
  To: linux-kernel, netdev

[-- Attachment #1: Type: text/plain, Size: 4003 bytes --]

I've had occasional apparent hard lockups on one computer here for some time.
I'd previously been not doing much about it other than pressing the reset
button, since there was nothing which marked it as a kernel panic (no
blinkenlights; USB keyboard). However, I'd decided to make use of netconsole;
this eventually logged the panic at the end of this message.

The kernel is 2.6.23.17-hrt5 (I had to do a few manual fixups, but nothing
non-trivial); the DVB modules come from v4l-dvb (cset 127f67dea087); the
attached mouse patch is in use (my mouse is weird).

The board is an Abit KN8 v1.1 (nForce 4); on-board ethernet is in use. Full
kernel log & config are attached.


Unable to handle kernel NULL pointer dereference at 000000000000007f RIP: 
 [<ffffffff80426872>] tcp_v4_rcv+0x2ae/0x8c8
PGD 3bb9a067 PUD 1de4d067 PMD 0 
Oops: 0000 [1] 
CPU 0 
Modules linked in: vfat fat usb_storage sd_mod mt2060 dvb_usb_dib0700
dib7000p dib7000m dvb_usb dib3000mc dibx000_common dib0070 snd_rtctimer
dvb_pll cx22702 cx88_dvb cx8802 cx88xx videodev v4l1_compat ir_common
tveeprom btcx_risc videobuf_dvb videobuf_dma_sg videobuf_core dvb_core radeon
drm ip6t_owner ip6t_LOG xt_tcpudp ip6t_REJECT nf_conntrack_ipv6 xt_state
nf_conntrack ip6table_mangle ip6table_filter ip6_tables x_tables
snd_emu10k1_synth snd_emux_synth snd_seq_virmidi snd_seq_midi_emul
snd_emu10k1 snd_seq_dummy snd_seq_oss snd_seq_midi snd_seq_midi_event snd_seq
snd_intel8x0 snd_rawmidi snd_ac97_codec ac97_bus snd_pcm_oss snd_mixer_oss
snd_pcm snd_seq_device snd_timer snd_util_mem snd_hwdep snd snd_page_alloc
Pid: 0, comm: swapper Not tainted 2.6.23.17-hrt5 #1
RIP: 0010:[<ffffffff80426872>]  [<ffffffff80426872>] tcp_v4_rcv+0x2ae/0x8c8
RSP: 0018:ffffffff8062ade0  EFLAGS: 00010202
RAX: 000000000000007f RBX: ffff81003fe98a80 RCX: 00000000b7627522
RDX: ffff81003fb6f7f0 RSI: 0000000014756f7f RDI: 0000000038627a43
RBP: ffff810024dd1032 R08: 0000000089404612 R09: 0500a8c04cf31d52
R10: ffff81003fe98940 R11: 0000000000000002 R12: ffff81003fe98a80
R13: 000000000500a8c0 R14: 00000001085fd2e0 R15: ffff810024dd101e
FS:  0000000040800950(0000) GS:ffffffff805eb000(0000) knlGS:00000000f74f26c0
CS:  0010 DS: 0018 ES: 0018 CR0: 000000008005003b
CR2: 000000000000007f CR3: 00000000266b3000 CR4: 00000000000006e0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000ffff4ff0 DR7: 0000000000000400
Process swapper (pid: 0, threadinfo ffffffff805f4000, task ffffffff805a5360)
Stack:  ffff81003e8e2400 ffff81003fe98a80 ffffffff805e3ed0 0000000000000000
 ffffffff8062aef4 00000001085fd2e0 0000000000000040 ffffffff8040d550
 ffff81003fe98a80 ffff81003fe98a80 ffff810024dd101e ffff81003fe98a80
Call Trace:
 <IRQ>  [<ffffffff8040d550>] ip_local_deliver+0x19e/0x22a
 [<ffffffff8040d37b>] ip_rcv+0x477/0x4ae
 [<ffffffff803f852b>] process_backlog+0x7d/0xf6
 [<ffffffff80210ee9>] nommu_map_single+0x2b/0x42
 [<ffffffff803f86bc>] net_rx_action+0x85/0x15a
 [<ffffffff8022b7b3>] __do_softirq+0x4f/0x9c
 [<ffffffff8020c10c>] call_softirq+0x1c/0x28
 [<ffffffff8020d6a4>] do_softirq+0x2c/0x7d
 [<ffffffff8022b726>] irq_exit+0x3f/0x7d
 [<ffffffff8020d9d1>] do_IRQ+0x11e/0x135
 [<ffffffff8020a6f9>] default_idle+0x0/0x3a
 [<ffffffff8020b961>] ret_from_intr+0x0/0xa
 <EOI>  [<ffffffff8020a6f9>] default_idle+0x0/0x3a
 [<ffffffff8020a71f>] default_idle+0x26/0x3a
 [<ffffffff8020a783>] cpu_idle+0x50/0x74
 [<ffffffff805f7935>] start_kernel+0x252/0x25e
 [<ffffffff805f712a>] _sinittext+0x12a/0x12e

Code: 48 8b 08 0f 18 09 48 8d 58 f8 39 73 2c 75 e9 eb c9 48 8b 42 
RIP  [<ffffffff80426872>] tcp_v4_rcv+0x2ae/0x8c8
 RSP <ffffffff8062ade0>
CR2: 000000000000007f
Kernel panic - not syncing: Aiee, killing interrupt handler!

-- 
| Darren Salt    | linux or ds at              | nr. Ashington, | Toon
| RISC OS, Linux | youmustbejoking,demon,co,uk | Northumberland | Army
| + Output less CO2 => avoid boiling weather.     TIME IS RUNNING OUT *FAST*.

There is nothing so small that it can't be blown out of all proportion.


[-- Attachment #2: crash.log.gz --]
[-- Type: application/x-gzip, Size: 8886 bytes --]

[-- Attachment #3: config.gz --]
[-- Type: application/x-gzip, Size: 11315 bytes --]

[-- Attachment #4: browser-mouse.patch --]
[-- Type: application/octet-stream, Size: 11977 bytes --]

Button and wheel translation for Chic Technology Corp Browser Mouse via USB

This patch implements a USB HID quirk for Chic Technology Corp Browser Mouse
devices. These are sold in at least two guises; I've encountered one, the
Advent 5-button wireless rechargeable optical mouse.

This mouse has the usual inputs common to ExplorerPS/2 mice; additionally,
the wheel is tiltable and there's an extra button which the documenation
calls a "hot-key button".

It identifies itself as
  Vendor=0x5fe ProdID=0011 Rev= 1.01
  Manufacturer=Wireless Mouse
  Product=Wireless Mouse
(but see also http://www.qbik.ch/usb/devices/showdescr.php?id=3244 for an
apparently different device with the same vendor and product IDs).

Its buttons behave identically whether the mouse is connected via PS/2 or
USB. I've tested with a USB snooper on a Windows box (with the mouse's
driver installed) and it still reported the buttons as I'd already observed
on Linux.

The mouse always reports the extra three buttons as follows:

* Pushing the wheel to the left  => buttons 3 and 4 (middle + side).
* Pushing the wheel to the right => buttons 3 and 5 (middle + extra).
* Pressing the "hot-key" button  => buttons 2 and 4 (right + side).

The quirk handles these by making the wheel pushes look like REL_HWHEEL
events and the hot-key button look like BTN_FORWARD. (X needs to be told that
the mouse has 10 buttons. The hot-key button could be mapped to BTN_TASK,
making it a "12-button" mouse as far as X is concerned.)

REL_HWHEEL events are repeated using an extra timer which is allocated as
part of struct hid_device.

Signed-off-by: Darren Salt <linux@youmustbejoking.demon.co.uk>

diff -ur linux-2.6.23.orig/drivers/hid/hid-core.c linux-2.6.23/drivers/hid/hid-core.c
--- linux-2.6.23.orig/drivers/hid/hid-core.c	2007-12-06 23:39:40.000000000 +0000
+++ linux-2.6.23/drivers/hid/hid-core.c	2007-12-06 23:41:38.000000000 +0000
@@ -863,6 +863,9 @@
 				hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt);
 	}
 
+	if (hid->claimed & HID_CLAIMED_INPUT)
+		hidinput_hid_quirks(hid, field);
+
 	memcpy(field->value, value, count * sizeof(__s32));
 exit:
 	kfree(value);
diff -ur linux-2.6.23.orig/drivers/hid/hid-input.c linux-2.6.23/drivers/hid/hid-input.c
--- linux-2.6.23.orig/drivers/hid/hid-input.c	2007-12-06 23:39:40.000000000 +0000
+++ linux-2.6.23/drivers/hid/hid-input.c	2007-12-06 23:42:54.000000000 +0000
@@ -334,6 +334,86 @@
 }
 
 
+struct hid_pseudobutton_mappings_t {
+	__u16 mask, type, button;
+	__s16 value;
+};
+
+/* Button mappings for the Chic browser mouse (USB ID 05FE:0011).
+ * This is sold as (at least):
+ *	* Advent 5-button wireless rechargeable mouse
+ * It has three extra buttons (wheel pushed sideways, task button) which are
+ * signalled as pairs of standard buttons.
+ */
+static const struct hid_pseudobutton_mappings_t chic_browser_mouse_buttons[] = {
+#if 0
+	{ 1 << 1 | 1 << 3, EV_KEY, BTN_TASK, 1 },	/* 2 and 4 (hot-key) */
+	{ 1 << 2 | 1 << 3, EV_KEY, BTN_BACK, 1 },	/* 3 and 4 (wheel left) */
+	{ 1 << 2 | 1 << 4, EV_KEY, BTN_FORWARD, 1 },	/* 3 and 5 (wheel right) */
+#else
+	{ 1 << 1 | 1 << 3, EV_KEY, BTN_FORWARD, 1 },	/* 2 and 4 (hot-key) */
+	{ 1 << 2 | 1 << 3, EV_REL, REL_HWHEEL, -1 },	/* 3 and 4 (wheel left) */
+	{ 1 << 2 | 1 << 4, EV_REL, REL_HWHEEL, 1 },	/* 3 and 5 (wheel right) */
+#endif
+	{}
+};
+
+/* Repeat for e.g. pseudo-wheels.  We use the input device's own repeat values. */
+static void hidinput_repeat_event(unsigned long data)
+{
+	struct input_dev *input = (void *) data;
+	struct hid_device *device = input->private;
+
+	if (!device->repeat.value)
+		return;
+
+	input_event(input, device->repeat.type, device->repeat.button, device->repeat.value);
+	input_sync(input);
+
+	if (input->rep[REP_PERIOD])
+		mod_timer(&device->repeat.timer, jiffies + msecs_to_jiffies(input->rep[REP_PERIOD]));
+}
+
+static void hidinput_register_pseudobuttons (struct hid_input *hidinput,
+					     struct hid_field *field,
+					     struct hid_usage *usage,
+					     unsigned long *bit,
+					     const struct hid_pseudobutton_mappings_t *buttons,
+					     int allow_repeat)
+{
+	int i;
+	int have_wheel = 0;
+	struct hid_device *device = hidinput->input->private;
+
+	for (i = 0; buttons[i].mask; ++i)
+	{
+		if (usage->type != buttons[i].type)
+			continue;
+
+		switch (buttons[i].type)
+		{
+			case EV_KEY:
+				if (usage->code == BTN_EXTRA)
+					set_bit(buttons[i].button, bit);
+				break;
+			case EV_REL:
+				if (usage->code == REL_WHEEL) {
+					have_wheel = allow_repeat;
+					set_bit(buttons[i].button, bit);
+				}
+				break;
+		}
+	}
+
+	/* If the quirk has introduced an extra wheel (for example),
+	 * we need to handle our own repeats. */
+	if (have_wheel && !device->repeat.timer.function) {
+		init_timer(&device->repeat.timer);
+		device->repeat.timer.data = (long) hidinput->input;
+		device->repeat.timer.function = hidinput_repeat_event;
+	}
+}
+
 static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
 				     struct hid_usage *usage)
 {
@@ -824,6 +904,9 @@
 			map_key(BTN_1);
 	}
 
+	if (device->quirks & HID_QUIRK_CHIC_PSEUDOBUTTONS_HACK)
+		hidinput_register_pseudobuttons (hidinput, field, usage, bit, chic_browser_mouse_buttons, 1);
+
 	if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5)) &&
 		 (usage->type == EV_REL) && (usage->code == REL_WHEEL))
 			set_bit(REL_HWHEEL, bit);
@@ -924,6 +1007,12 @@
 		return;
 	}
 
+	if (!(hid->quirks & HID_QUIRK_CHIC_PSEUDOBUTTONS_HACK) && 
+	    (hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) {
+		input_event(input, usage->type, REL_HWHEEL, value);
+		return;
+	}
+
 	if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) {
 		input_event(input, usage->type, REL_HWHEEL, value);
 		return;
@@ -973,9 +1062,20 @@
 		return;
 	}
 
+	/* For quirks where one physical button looks like (at least) two other physical buttons */
+	if ((usage->type == EV_KEY) && (usage->hid > 0x00090000) && (usage->hid <= 0x00090010)) {
+		if (value)
+			hid->btn_state |= 1 << (usage->hid - 0x00090001);
+		else
+			hid->btn_state &= ~(1 << (usage->hid - 0x00090001));
+	}
+
 	if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */
 		return;
 
+	if ((usage->type == EV_KEY) && (hid->quirks & HID_QUIRK_CHIC_PSEUDOBUTTONS_HACK)) /* some buttons may have quirks - *don't* generate events just yet */
+		return;
+
 	if ((usage->type == EV_ABS) && (field->flags & HID_MAIN_ITEM_RELATIVE) &&
 			(usage->code == ABS_VOLUME)) {
 		int count = abs(value);
@@ -1006,6 +1106,60 @@
 }
 EXPORT_SYMBOL_GPL(hidinput_report_event);
 
+static void hidinput_hid_quirk_process_pseudobuttons (struct hid_device *hid, struct input_dev *input,
+						      const struct hid_pseudobutton_mappings_t *mapping)
+{
+	__u16 buttons = hid->btn_state;
+	__u16 previous = hid->btn_prev_state;
+	int i;
+
+	hid->btn_prev_state = hid->btn_state;
+
+	for (i = 0; mapping[i].mask; ++i) {
+		/* both clear -> both set => button is now pressed */
+		if (!(hid->btn_quirks & (1 << i))
+		    && ((previous & mapping[i].mask) == 0)
+		    && ((buttons & mapping[i].mask) == mapping[i].mask)) {
+			buttons &= ~mapping[i].mask;
+			hid->btn_quirks |= 1 << i;
+			input_event (input, mapping[i].type, mapping[i].button, mapping[i].value);
+			/* If it's something like a pseudowheel, start repeating it. */
+			if (((mapping[i].button == REL_WHEEL) || (mapping[i].button == REL_HWHEEL)) &&
+			    hid->repeat.timer.function && input->rep[REP_PERIOD] && input->rep[REP_DELAY]) {
+				hid->repeat.type = mapping[i].type;
+				hid->repeat.button = mapping[i].button;
+				hid->repeat.value = mapping[i].value;
+				mod_timer(&hid->repeat.timer, jiffies + msecs_to_jiffies(input->rep[REP_DELAY]));
+			}
+		}
+		/* both set -> either clear => button is now released */
+		else
+		if ((hid->btn_quirks & (1 << i))
+		    && ((previous & mapping[i].mask) == mapping[i].mask)
+		    && ((buttons & mapping[i].mask) != mapping[i].mask)) {
+			buttons &= ~mapping[i].mask;
+			hid->btn_quirks &= ~(1 << i);
+			input_event (input, mapping[i].type, mapping[i].button, 0);
+			if ((mapping[i].button == REL_WHEEL) || (mapping[i].button == REL_HWHEEL))
+				hid->repeat.value = 0;
+		}
+	}
+
+	for (i = 0; i < 16; ++i)
+		if ((buttons ^ previous) & (1 << i))
+			input_event (input, EV_KEY, BTN_MOUSE + i, (buttons >> i) & 1);
+}
+
+void hidinput_hid_quirks(struct hid_device *hid, struct hid_field *field)
+{
+	if (!field->hidinput)
+		return;
+	/* Chic browser mouse (sold as, at least, Advent 5-button) */
+	if (hid->quirks & HID_QUIRK_CHIC_PSEUDOBUTTONS_HACK)
+		hidinput_hid_quirk_process_pseudobuttons (hid, field->hidinput->input, chic_browser_mouse_buttons);
+}
+EXPORT_SYMBOL_GPL(hidinput_hid_quirks);
+
 int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field)
 {
 	struct hid_report *report;
@@ -1120,6 +1274,10 @@
 	if (hidinput)
 		input_register_device(hidinput->input);
 
+	hid->btn_state = 0;
+	hid->btn_prev_state = 0;
+	hid->btn_quirks = 0;
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(hidinput_connect);
@@ -1129,6 +1287,11 @@
 	struct hid_input *hidinput, *next;
 
 	list_for_each_entry_safe(hidinput, next, &hid->inputs, list) {
+		/* Stop any repeat timer which may have been registered. */
+		struct hid_device *device = hidinput->input->private;
+		if (device->repeat.timer.function)
+			del_timer_sync(&device->repeat.timer);
+		/* Unregister the device and clean up. */
 		list_del(&hidinput->list);
 		input_unregister_device(hidinput->input);
 		kfree(hidinput);
diff -ur linux-2.6.23.orig/drivers/hid/usbhid/hid-quirks.c linux-2.6.23/drivers/hid/usbhid/hid-quirks.c
--- linux-2.6.23.orig/drivers/hid/usbhid/hid-quirks.c	2007-12-06 23:39:40.000000000 +0000
+++ linux-2.6.23/drivers/hid/usbhid/hid-quirks.c	2007-12-06 23:41:38.000000000 +0000
@@ -82,6 +82,7 @@
 #define USB_DEVICE_ID_CHERRY_CYMOTION	0x0023
 
 #define USB_VENDOR_ID_CHIC		0x05fe
+#define USB_DEVICE_ID_CHIC_BROWSER_MOUSE 0x0011
 #define USB_DEVICE_ID_CHIC_GAMEPAD	0x0014
 
 #define USB_VENDOR_ID_CIDC		0x1677
@@ -355,6 +356,7 @@
 
 	{ USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 },
 	{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_5 },
+	{ USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_BROWSER_MOUSE, HID_QUIRK_CHIC_PSEUDOBUTTONS_HACK },
 
 	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS },
 
diff -ur linux-2.6.23.orig/include/linux/hid.h linux-2.6.23/include/linux/hid.h
--- linux-2.6.23.orig/include/linux/hid.h	2007-12-06 23:39:49.000000000 +0000
+++ linux-2.6.23/include/linux/hid.h	2007-12-06 23:43:15.000000000 +0000
@@ -276,6 +276,7 @@
 #define HID_QUIRK_HIDINPUT			0x00200000
 #define HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL	0x00400000
 #define HID_QUIRK_LOGITECH_EXPANDED_KEYMAP	0x00800000
+#define HID_QUIRK_CHIC_PSEUDOBUTTONS_HACK	0x01000000
 
 /*
  * Separate quirks for runtime report descriptor fixup
@@ -462,6 +463,16 @@
 	unsigned long pb_pressed_fn[NBITS(KEY_MAX)];
 	unsigned long pb_pressed_numlock[NBITS(KEY_MAX)];
 #endif
+
+	/* For quirks where one physical button looks like (at least) two other physical buttons */
+	__u16 btn_state, btn_prev_state;				/* Button map data */
+	__u32 btn_quirks;						/* Which of the extra buttons are active */
+
+	struct {
+		__u16 type, button;
+		__s16 value;
+		struct timer_list timer;
+	} repeat;
 };
 
 #define HID_GLOBAL_STACK_SIZE 4
@@ -504,6 +515,7 @@
 
 extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32);
 extern void hidinput_report_event(struct hid_device *hid, struct hid_report *report);
+extern void hidinput_hid_quirks(struct hid_device *, struct hid_field *);
 extern int hidinput_connect(struct hid_device *);
 extern void hidinput_disconnect(struct hid_device *);
 

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2008-03-09 14:30 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-03-09 14:24 Kernel panic (networking-related?) Darren Salt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).