a 3.6 commit breaks serial synth indexing

covici at ccs.covici.com covici at ccs.covici.com
Sun Dec 23 02:27:57 EST 2012


Hi.  In my normal update process, I discovered that if I use
3.7.0-gentoo, indexing for my speakout synth no longer works.  I then
started on a git hunt for the bug -- too much work -- and found that the
following commit seems to be the culprit:
# bad: [4369c64c79a22b98d3b7eff9d089196cd878a10a] Input: Send events one
packet at a time

Anyone have a clue as to what is going on here and to whom to report
such a thing so this can be fixed?

Thanks in advance for any assistance.

Here is the actual patch(I think).

diff --git a/drivers/input/input.c b/drivers/input/input.c
index 5244f3d..fbe522d 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -47,8 +47,6 @@ static DEFINE_MUTEX(input_mutex);
 
 static struct input_handler *input_table[8];
 
-static const struct input_value input_value_sync = { EV_SYN, SYN_REPORT, 1 };
-
 static inline int is_event_supported(unsigned int code,
 				     unsigned long *bm, unsigned int max)
 {
@@ -92,81 +90,46 @@ static void input_stop_autorepeat(struct input_dev *dev)
  * filtered out, through all open handles. This function is called with
  * dev->event_lock held and interrupts disabled.
  */
-static unsigned int input_to_handler(struct input_handle *handle,
-			struct input_value *vals, unsigned int count)
+static void input_pass_event(struct input_dev *dev,
+			     unsigned int type, unsigned int code, int value)
 {
-	struct input_handler *handler = handle->handler;
-	struct input_value *end = vals;
-	struct input_value *v;
-
-	for (v = vals; v != vals + count; v++) {
-		if (handler->filter &&
-		    handler->filter(handle, v->type, v->code, v->value))
-			continue;
-		if (end != v)
-			*end = *v;
-		end++;
-	}
-
-	count = end - vals;
-	if (!count)
-		return 0;
+	struct input_handler *handler;
+	struct input_handle *handle;
 
-	if (handler->events)
-		handler->events(handle, vals, count);
-	else if (handler->event)
-		for (v = vals; v != end; v++)
-			handler->event(handle, v->type, v->code, v->value);
+	rcu_read_lock();
 
-	return count;
-}
+	handle = rcu_dereference(dev->grab);
+	if (handle)
+		handle->handler->event(handle, type, code, value);
+	else {
+		bool filtered = false;
 
-/*
- * Pass values first through all filters and then, if event has not been
- * filtered out, through all open handles. This function is called with
- * dev->event_lock held and interrupts disabled.
- */
-static void input_pass_values(struct input_dev *dev,
-			      struct input_value *vals, unsigned int count)
-{
-	struct input_handle *handle;
-	struct input_value *v;
+		list_for_each_entry_rcu(handle, &dev->h_list, d_node) {
+			if (!handle->open)
+				continue;
 
-	if (!count)
-		return;
+			handler = handle->handler;
+			if (!handler->filter) {
+				if (filtered)
+					break;
 
-	rcu_read_lock();
+				handler->event(handle, type, code, value);
 
-	handle = rcu_dereference(dev->grab);
-	if (handle) {
-		count = input_to_handler(handle, vals, count);
-	} else {
-		list_for_each_entry_rcu(handle, &dev->h_list, d_node)
-			if (handle->open)
-				count = input_to_handler(handle, vals, count);
+			} else if (handler->filter(handle, type, code, value))
+				filtered = true;
+		}
 	}
 
 	rcu_read_unlock();
 
-	add_input_randomness(vals->type, vals->code, vals->value);
-
 	/* trigger auto repeat for key events */
-	for (v = vals; v != vals + count; v++) {
-		if (v->type == EV_KEY && v->value != 2) {
-			if (v->value)
-				input_start_autorepeat(dev, v->code);
-			else
-				input_stop_autorepeat(dev);
-		}
+	if (type == EV_KEY && value != 2) {
+		if (value)
+			input_start_autorepeat(dev, code);
+		else
+			input_stop_autorepeat(dev);
 	}
-}
 
-static void input_pass_event(struct input_dev *dev,
-			     unsigned int type, unsigned int code, int value)
-{
-	struct input_value vals[] = { { type, code, value } };
-
-	input_pass_values(dev, vals, ARRAY_SIZE(vals));
 }
 
 /*
@@ -183,12 +146,18 @@ static void input_repeat_key(unsigned long data)
 
 	if (test_bit(dev->repeat_key, dev->key) &&
 	    is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) {
-		struct input_value vals[] =  {
-			{ EV_KEY, dev->repeat_key, 2 },
-			input_value_sync
-		};
 
-		input_pass_values(dev, vals, ARRAY_SIZE(vals));
+		input_pass_event(dev, EV_KEY, dev->repeat_key, 2);
+
+		if (dev->sync) {
+			/*
+			 * Only send SYN_REPORT if we are not in a middle
+			 * of driver parsing a new hardware packet.
+			 * Otherwise assume that the driver will send
+			 * SYN_REPORT once it's done.
+			 */
+			input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
+		}
 
 		if (dev->rep[REP_PERIOD])
 			mod_timer(&dev->timer, jiffies +
@@ -201,8 +170,6 @@ static void input_repeat_key(unsigned long data)
 #define INPUT_IGNORE_EVENT	0
 #define INPUT_PASS_TO_HANDLERS	1
 #define INPUT_PASS_TO_DEVICE	2
-#define INPUT_SLOT		4
-#define INPUT_FLUSH		8
 #define INPUT_PASS_TO_ALL	(INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
 
 static int input_handle_abs_event(struct input_dev *dev,
@@ -249,14 +216,14 @@ static int input_handle_abs_event(struct input_dev *dev,
 	/* Flush pending "slot" event */
 	if (is_mt_event && mt && mt->slot != input_abs_get_val(dev, ABS_MT_SLOT)) {
 		input_abs_set_val(dev, ABS_MT_SLOT, mt->slot);
-		return INPUT_PASS_TO_HANDLERS | INPUT_SLOT;
+		input_pass_event(dev, EV_ABS, ABS_MT_SLOT, mt->slot);
 	}
 
 	return INPUT_PASS_TO_HANDLERS;
 }
 
-static int input_get_disposition(struct input_dev *dev,
-			  unsigned int type, unsigned int code, int value)
+static void input_handle_event(struct input_dev *dev,
+			       unsigned int type, unsigned int code, int value)
 {
 	int disposition = INPUT_IGNORE_EVENT;
 
@@ -269,9 +236,13 @@ static int input_get_disposition(struct input_dev *dev,
 			break;
 
 		case SYN_REPORT:
-			disposition = INPUT_PASS_TO_HANDLERS | INPUT_FLUSH;
+			if (!dev->sync) {
+				dev->sync = true;
+				disposition = INPUT_PASS_TO_HANDLERS;
+			}
 			break;
 		case SYN_MT_REPORT:
+			dev->sync = false;
 			disposition = INPUT_PASS_TO_HANDLERS;
 			break;
 		}
@@ -356,48 +327,14 @@ static int input_get_disposition(struct input_dev *dev,
 		break;
 	}
 
-	return disposition;
-}
-
-static void input_handle_event(struct input_dev *dev,
-			       unsigned int type, unsigned int code, int value)
-{
-	int disposition;
-
-	disposition = input_get_disposition(dev, type, code, value);
+	if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
+		dev->sync = false;
 
 	if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
 		dev->event(dev, type, code, value);
 
-	if (!dev->vals)
-		return;
-
-	if (disposition & INPUT_PASS_TO_HANDLERS) {
-		struct input_value *v;
-
-		if (disposition & INPUT_SLOT) {
-			v = &dev->vals[dev->num_vals++];
-			v->type = EV_ABS;
-			v->code = ABS_MT_SLOT;
-			v->value = dev->mt->slot;
-		}
-
-		v = &dev->vals[dev->num_vals++];
-		v->type = type;
-		v->code = code;
-		v->value = value;
-	}
-
-	if (disposition & INPUT_FLUSH) {
-		if (dev->num_vals >= 2)
-			input_pass_values(dev, dev->vals, dev->num_vals);
-		dev->num_vals = 0;
-	} else if (dev->num_vals >= dev->max_vals - 2) {
-		dev->vals[dev->num_vals++] = input_value_sync;
-		input_pass_values(dev, dev->vals, dev->num_vals);
-		dev->num_vals = 0;
-	}
-
+	if (disposition & INPUT_PASS_TO_HANDLERS)
+		input_pass_event(dev, type, code, value);
 }
 
 /**
@@ -425,6 +362,7 @@ void input_event(struct input_dev *dev,
 	if (is_event_supported(type, dev->evbit, EV_MAX)) {
 
 		spin_lock_irqsave(&dev->event_lock, flags);
+		add_input_randomness(type, code, value);
 		input_handle_event(dev, type, code, value);
 		spin_unlock_irqrestore(&dev->event_lock, flags);
 	}
@@ -903,12 +841,10 @@ int input_set_keycode(struct input_dev *dev,
 	if (test_bit(EV_KEY, dev->evbit) &&
 	    !is_event_supported(old_keycode, dev->keybit, KEY_MAX) &&
 	    __test_and_clear_bit(old_keycode, dev->key)) {
-		struct input_value vals[] =  {
-			{ EV_KEY, old_keycode, 0 },
-			input_value_sync
-		};
 
-		input_pass_values(dev, vals, ARRAY_SIZE(vals));
+		input_pass_event(dev, EV_KEY, old_keycode, 0);
+		if (dev->sync)
+			input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
 	}
 
  out:
@@ -1490,7 +1426,6 @@ static void input_dev_release(struct device *device)
 	input_ff_destroy(dev);
 	input_mt_destroy_slots(dev);
 	kfree(dev->absinfo);
-	kfree(dev->vals);
 	kfree(dev);
 
 	module_put(THIS_MODULE);
@@ -1911,11 +1846,6 @@ int input_register_device(struct input_dev *dev)
 	if (dev->hint_events_per_packet < packet_size)
 		dev->hint_events_per_packet = packet_size;
 
-	dev->max_vals = max(dev->hint_events_per_packet, packet_size) + 2;
-	dev->vals = kcalloc(dev->max_vals, sizeof(*dev->vals), GFP_KERNEL);
-	if (!dev->vals)
-		return -ENOMEM;
-
 	/*
 	 * If delay and period are pre-set by the driver, then autorepeating
 	 * is handled by the driver itself and we don't do it in input.c.
diff --git a/include/linux/input.h b/include/linux/input.h
index ba48743..9da4f57 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -1169,18 +1169,6 @@ struct ff_effect {
 #include <linux/mod_devicetable.h>
 
 /**
- * struct input_value - input value representation
- * @type: type of value (EV_KEY, EV_ABS, etc)
- * @code: the value code
- * @value: the value
- */
-struct input_value {
-	__u16 type;
-	__u16 code;
-	__s32 value;
-};
-
-/**
  * struct input_dev - represents an input device
  * @name: name of the device
  * @phys: physical path to the device in the system hierarchy
@@ -1252,6 +1240,7 @@ struct input_value {
  *	last user closes the device
  * @going_away: marks devices that are in a middle of unregistering and
  *	causes input_open_device*() fail with -ENODEV.
+ * @sync: set to %true when there were no new events since last EV_SYN
  * @dev: driver model's view of this device
  * @h_list: list of input handles associated with the device. When
  *	accessing the list dev->mutex must be held
@@ -1316,14 +1305,12 @@ struct input_dev {
 	unsigned int users;
 	bool going_away;
 
+	bool sync;
+
 	struct device dev;
 
 	struct list_head	h_list;
 	struct list_head	node;
-
-	unsigned int num_vals;
-	unsigned int max_vals;
-	struct input_value *vals;
 };
 #define to_input_dev(d) container_of(d, struct input_dev, dev)
 
@@ -1384,9 +1371,6 @@ struct input_handle;
  * @event: event handler. This method is being called by input core with
  *	interrupts disabled and dev->event_lock spinlock held and so
  *	it may not sleep
- * @events: event sequence handler. This method is being called by
- *	input core with interrupts disabled and dev->event_lock
- *	spinlock held and so it may not sleep
  * @filter: similar to @event; separates normal event handlers from
  *	"filters".
  * @match: called after comparing device's id with handler's id_table
@@ -1423,8 +1407,6 @@ struct input_handler {
 	void *private;
 
 	void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
-	void (*events)(struct input_handle *handle,
-		       const struct input_value *vals, unsigned int count);
 	bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
 	bool (*match)(struct input_handler *handler, struct input_dev *dev);
 	int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);

-- 
Your life is like a penny.  You're going to lose it.  The question is:
How do
you spend it?

         John Covici
         covici at ccs.covici.com


More information about the Speakup mailing list