Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1ad346a9 authored by Jiri Kosina's avatar Jiri Kosina
Browse files

Merge branch 'for-next' of git://github.com/rydberg/linux into from-henrik



Pull Input and HID updates for 3.7 from Henrik Rydberg:
"The tree contains input core changes, Acked by Dmitry, which substantially
reduces the irqsoff latency for all input devices. It also contains MT changes
which allows further memory reduction, speedup and hardware support in the HID
Multitouch driver. Lastly, you get the conversion of the bcm5974 driver to
MT-B, which due to the mixed dependency of the tree fits better here than
anywhere else."

Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parents 5b6e7f1c 51c80b74
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -283,6 +283,9 @@
#define USB_VENDOR_ID_EMS		0x2006
#define USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II 0x0118

#define USB_VENDOR_ID_FLATFROG		0x25b5
#define USB_DEVICE_ID_MULTITOUCH_3200	0x0002

#define USB_VENDOR_ID_ESSENTIAL_REALITY	0x0d7f
#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100

+9 −2
Original line number Diff line number Diff line
@@ -1154,6 +1154,7 @@ static void report_features(struct hid_device *hid)

int hidinput_connect(struct hid_device *hid, unsigned int force)
{
	struct hid_driver *drv = hid->driver;
	struct hid_report *report;
	struct hid_input *hidinput = NULL;
	struct input_dev *input_dev;
@@ -1228,6 +1229,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
				 * UGCI) cram a lot of unrelated inputs into the
				 * same interface. */
				hidinput->report = report;
				if (drv->input_configured)
					drv->input_configured(hid, hidinput);
				if (input_register_device(hidinput->input))
					goto out_cleanup;
				hidinput = NULL;
@@ -1235,8 +1238,12 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
		}
	}

	if (hidinput && input_register_device(hidinput->input))
	if (hidinput) {
		if (drv->input_configured)
			drv->input_configured(hid, hidinput);
		if (input_register_device(hidinput->input))
			goto out_cleanup;
	}

	return 0;

+1 −1
Original line number Diff line number Diff line
@@ -392,7 +392,7 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd

	__set_bit(EV_ABS, input->evbit);

	error = input_mt_init_slots(input, 16);
	error = input_mt_init_slots(input, 16, 0);
	if (error)
		return error;
	input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255 << 2,
+85 −100
Original line number Diff line number Diff line
@@ -51,12 +51,12 @@ MODULE_LICENSE("GPL");
#define MT_QUIRK_VALID_IS_INRANGE	(1 << 5)
#define MT_QUIRK_VALID_IS_CONFIDENCE	(1 << 6)
#define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE	(1 << 8)
#define MT_QUIRK_NO_AREA		(1 << 9)

struct mt_slot {
	__s32 x, y, p, w, h;
	__s32 contactid;	/* the device ContactID assigned to this slot */
	bool touch_state;	/* is the touch valid? */
	bool seen_in_this_frame;/* has this slot been updated */
};

struct mt_class {
@@ -92,8 +92,9 @@ struct mt_device {
	__u8 touches_by_report;	/* how many touches are present in one report:
				* 1 means we should use a serial protocol
				* > 1 means hybrid (multitouch) protocol */
	bool serial_maybe;	/* need to check for serial protocol */
	bool curvalid;		/* is the current contact valid? */
	struct mt_slot *slots;
	unsigned mt_flags;	/* flags to pass to input-mt */
};

/* classes of device behavior */
@@ -115,6 +116,7 @@ struct mt_device {
#define MT_CLS_EGALAX_SERIAL			0x0104
#define MT_CLS_TOPSEED				0x0105
#define MT_CLS_PANASONIC			0x0106
#define MT_CLS_FLATFROG				0x0107

#define MT_DEFAULT_MAXCONTACT	10

@@ -134,25 +136,6 @@ static int cypress_compute_slot(struct mt_device *td)
		return -1;
}

static int find_slot_from_contactid(struct mt_device *td)
{
	int i;
	for (i = 0; i < td->maxcontacts; ++i) {
		if (td->slots[i].contactid == td->curdata.contactid &&
			td->slots[i].touch_state)
			return i;
	}
	for (i = 0; i < td->maxcontacts; ++i) {
		if (!td->slots[i].seen_in_this_frame &&
			!td->slots[i].touch_state)
			return i;
	}
	/* should not occurs. If this happens that means
	 * that the device sent more touches that it says
	 * in the report descriptor. It is ignored then. */
	return -1;
}

static struct mt_class mt_classes[] = {
	{ .name = MT_CLS_DEFAULT,
		.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP },
@@ -190,7 +173,9 @@ static struct mt_class mt_classes[] = {
			MT_QUIRK_SLOT_IS_CONTACTID,
		.sn_move = 2048,
		.sn_width = 128,
		.sn_height = 128 },
		.sn_height = 128,
		.maxcontacts = 60,
	},
	{ .name = MT_CLS_CYPRESS,
		.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
			MT_QUIRK_CYPRESS,
@@ -216,6 +201,12 @@ static struct mt_class mt_classes[] = {
		.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP,
		.maxcontacts = 4 },

	{ .name = MT_CLS_FLATFROG,
		.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
			MT_QUIRK_NO_AREA,
		.sn_move = 2048,
		.maxcontacts = 40,
	},
	{ }
};

@@ -319,24 +310,16 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
	* We need to ignore fields that belong to other collections
	* such as Mouse that might have the same GenericDesktop usages. */
	if (field->application == HID_DG_TOUCHSCREEN)
		set_bit(INPUT_PROP_DIRECT, hi->input->propbit);
		td->mt_flags |= INPUT_MT_DIRECT;
	else if (field->application != HID_DG_TOUCHPAD)
		return 0;

	/* In case of an indirect device (touchpad), we need to add
	 * specific BTN_TOOL_* to be handled by the synaptics xorg
	 * driver.
	 * We also consider that touchscreens providing buttons are touchpads.
	/*
	 * Model touchscreens providing buttons as touchpads.
	 */
	if (field->application == HID_DG_TOUCHPAD ||
	    (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON ||
	    cls->is_indirect) {
		set_bit(INPUT_PROP_POINTER, hi->input->propbit);
		set_bit(BTN_TOOL_FINGER, hi->input->keybit);
		set_bit(BTN_TOOL_DOUBLETAP, hi->input->keybit);
		set_bit(BTN_TOOL_TRIPLETAP, hi->input->keybit);
		set_bit(BTN_TOOL_QUADTAP, hi->input->keybit);
	}
	    (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON)
		td->mt_flags |= INPUT_MT_POINTER;

	/* eGalax devices provide a Digitizer.Stylus input which overrides
	 * the correct Digitizers.Finger X/Y ranges.
@@ -353,8 +336,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
					EV_ABS, ABS_MT_POSITION_X);
			set_abs(hi->input, ABS_MT_POSITION_X, field,
				cls->sn_move);
			/* touchscreen emulation */
			set_abs(hi->input, ABS_X, field, cls->sn_move);
			mt_store_field(usage, td, hi);
			td->last_field_index = field->index;
			return 1;
@@ -363,8 +344,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
					EV_ABS, ABS_MT_POSITION_Y);
			set_abs(hi->input, ABS_MT_POSITION_Y, field,
				cls->sn_move);
			/* touchscreen emulation */
			set_abs(hi->input, ABS_Y, field, cls->sn_move);
			mt_store_field(usage, td, hi);
			td->last_field_index = field->index;
			return 1;
@@ -388,9 +367,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
			td->last_field_index = field->index;
			return 1;
		case HID_DG_CONTACTID:
			if (!td->maxcontacts)
				td->maxcontacts = MT_DEFAULT_MAXCONTACT;
			input_mt_init_slots(hi->input, td->maxcontacts);
			mt_store_field(usage, td, hi);
			td->last_field_index = field->index;
			td->touches_by_report++;
@@ -398,6 +374,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
		case HID_DG_WIDTH:
			hid_map_usage(hi, usage, bit, max,
					EV_ABS, ABS_MT_TOUCH_MAJOR);
			if (!(cls->quirks & MT_QUIRK_NO_AREA))
				set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field,
					cls->sn_width);
			mt_store_field(usage, td, hi);
@@ -406,10 +383,12 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
		case HID_DG_HEIGHT:
			hid_map_usage(hi, usage, bit, max,
					EV_ABS, ABS_MT_TOUCH_MINOR);
			if (!(cls->quirks & MT_QUIRK_NO_AREA)) {
				set_abs(hi->input, ABS_MT_TOUCH_MINOR, field,
					cls->sn_height);
				input_set_abs_params(hi->input,
					ABS_MT_ORIENTATION, 0, 1, 0, 0);
			}
			mt_store_field(usage, td, hi);
			td->last_field_index = field->index;
			return 1;
@@ -418,9 +397,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
					EV_ABS, ABS_MT_PRESSURE);
			set_abs(hi->input, ABS_MT_PRESSURE, field,
				cls->sn_pressure);
			/* touchscreen emulation */
			set_abs(hi->input, ABS_PRESSURE, field,
				cls->sn_pressure);
			mt_store_field(usage, td, hi);
			td->last_field_index = field->index;
			return 1;
@@ -464,7 +440,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
	return -1;
}

static int mt_compute_slot(struct mt_device *td)
static int mt_compute_slot(struct mt_device *td, struct input_dev *input)
{
	__s32 quirks = td->mtclass.quirks;

@@ -480,42 +456,23 @@ static int mt_compute_slot(struct mt_device *td)
	if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE)
		return td->curdata.contactid - 1;

	return find_slot_from_contactid(td);
	return input_mt_get_slot_by_key(input, td->curdata.contactid);
}

/*
 * this function is called when a whole contact has been processed,
 * so that it can assign it to a slot and store the data there
 */
static void mt_complete_slot(struct mt_device *td)
static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
{
	td->curdata.seen_in_this_frame = true;
	if (td->curvalid) {
		int slotnum = mt_compute_slot(td);

		if (slotnum >= 0 && slotnum < td->maxcontacts)
			td->slots[slotnum] = td->curdata;
	}
	td->num_received++;
}


/*
 * this function is called when a whole packet has been received and processed,
 * so that it can decide what to send to the input layer.
 */
static void mt_emit_event(struct mt_device *td, struct input_dev *input)
{
	int i;
		int slotnum = mt_compute_slot(td, input);
		struct mt_slot *s = &td->curdata;

	for (i = 0; i < td->maxcontacts; ++i) {
		struct mt_slot *s = &(td->slots[i]);
		if ((td->mtclass.quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) &&
			!s->seen_in_this_frame) {
			s->touch_state = false;
		}
		if (slotnum < 0 || slotnum >= td->maxcontacts)
			return;

		input_mt_slot(input, i);
		input_mt_slot(input, slotnum);
		input_mt_report_slot_state(input, MT_TOOL_FINGER,
			s->touch_state);
		if (s->touch_state) {
@@ -532,24 +489,29 @@ static void mt_emit_event(struct mt_device *td, struct input_dev *input)
			input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
			input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
		}
		s->seen_in_this_frame = false;
	}

	td->num_received++;
}

	input_mt_report_pointer_emulation(input, true);
/*
 * this function is called when a whole packet has been received and processed,
 * so that it can decide what to send to the input layer.
 */
static void mt_sync_frame(struct mt_device *td, struct input_dev *input)
{
	input_mt_sync_frame(input);
	input_sync(input);
	td->num_received = 0;
}



static int mt_event(struct hid_device *hid, struct hid_field *field,
				struct hid_usage *usage, __s32 value)
{
	struct mt_device *td = hid_get_drvdata(hid);
	__s32 quirks = td->mtclass.quirks;

	if (hid->claimed & HID_CLAIMED_INPUT && td->slots) {
	if (hid->claimed & HID_CLAIMED_INPUT) {
		switch (usage->hid) {
		case HID_DG_INRANGE:
			if (quirks & MT_QUIRK_ALWAYS_VALID)
@@ -602,11 +564,11 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
		}

		if (usage->hid == td->last_slot_field)
			mt_complete_slot(td);
			mt_complete_slot(td, field->hidinput->input);

		if (field->index == td->last_field_index
			&& td->num_received >= td->num_expected)
			mt_emit_event(td, field->hidinput->input);
			mt_sync_frame(td, field->hidinput->input);

	}

@@ -685,6 +647,35 @@ static void mt_post_parse(struct mt_device *td)
	}
}

static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi)

{
	struct mt_device *td = hid_get_drvdata(hdev);
	struct mt_class *cls = &td->mtclass;
	struct input_dev *input = hi->input;

	/* Only initialize slots for MT input devices */
	if (!test_bit(ABS_MT_POSITION_X, input->absbit))
		return;

	if (!td->maxcontacts)
		td->maxcontacts = MT_DEFAULT_MAXCONTACT;

	mt_post_parse(td);
	if (td->serial_maybe)
		mt_post_parse_default_settings(td);

	if (cls->is_indirect)
		td->mt_flags |= INPUT_MT_POINTER;

	if (cls->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
		td->mt_flags |= INPUT_MT_DROP_UNUSED;

	input_mt_init_slots(input, td->maxcontacts, td->mt_flags);

	td->mt_flags = 0;
}

static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
	int ret, i;
@@ -722,6 +713,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
		goto fail;
	}

	if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID)
		td->serial_maybe = true;

	ret = hid_parse(hdev);
	if (ret != 0)
		goto fail;
@@ -730,20 +724,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
	if (ret)
		goto fail;

	mt_post_parse(td);

	if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID)
		mt_post_parse_default_settings(td);

	td->slots = kzalloc(td->maxcontacts * sizeof(struct mt_slot),
				GFP_KERNEL);
	if (!td->slots) {
		dev_err(&hdev->dev, "cannot allocate multitouch slots\n");
		hid_hw_stop(hdev);
		ret = -ENOMEM;
		goto fail;
	}

	ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group);

	mt_set_maxcontacts(hdev);
@@ -774,7 +754,6 @@ static void mt_remove(struct hid_device *hdev)
	struct mt_device *td = hid_get_drvdata(hdev);
	sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
	hid_hw_stop(hdev);
	kfree(td->slots);
	kfree(td);
	hid_set_drvdata(hdev, NULL);
}
@@ -892,6 +871,11 @@ static const struct hid_device_id mt_devices[] = {
		MT_USB_DEVICE(USB_VENDOR_ID_ELO,
			USB_DEVICE_ID_ELO_TS2515) },

	/* Flatfrog Panels */
	{ .driver_data = MT_CLS_FLATFROG,
		MT_USB_DEVICE(USB_VENDOR_ID_FLATFROG,
			USB_DEVICE_ID_MULTITOUCH_3200) },

	/* GeneralTouch panel */
	{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
		MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
@@ -1087,6 +1071,7 @@ static struct hid_driver mt_driver = {
	.remove = mt_remove,
	.input_mapping = mt_input_mapping,
	.input_mapped = mt_input_mapped,
	.input_configured = mt_input_configured,
	.feature_mapping = mt_feature_mapping,
	.usage_table = mt_grabbed_usages,
	.event = mt_event,
+53 −25
Original line number Diff line number Diff line
@@ -54,16 +54,9 @@ struct evdev_client {
static struct evdev *evdev_table[EVDEV_MINORS];
static DEFINE_MUTEX(evdev_table_mutex);

static void evdev_pass_event(struct evdev_client *client,
			     struct input_event *event,
			     ktime_t mono, ktime_t real)
static void __pass_event(struct evdev_client *client,
			 const struct input_event *event)
{
	event->time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ?
					mono : real);

	/* Interrupts are disabled, just acquire the lock. */
	spin_lock(&client->buffer_lock);

	client->buffer[client->head++] = *event;
	client->head &= client->bufsize - 1;

@@ -86,42 +79,74 @@ static void evdev_pass_event(struct evdev_client *client,
		client->packet_head = client->head;
		kill_fasync(&client->fasync, SIGIO, POLL_IN);
	}
}

static void evdev_pass_values(struct evdev_client *client,
			const struct input_value *vals, unsigned int count,
			ktime_t mono, ktime_t real)
{
	struct evdev *evdev = client->evdev;
	const struct input_value *v;
	struct input_event event;
	bool wakeup = false;

	event.time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ?
				      mono : real);

	/* Interrupts are disabled, just acquire the lock. */
	spin_lock(&client->buffer_lock);

	for (v = vals; v != vals + count; v++) {
		event.type = v->type;
		event.code = v->code;
		event.value = v->value;
		__pass_event(client, &event);
		if (v->type == EV_SYN && v->code == SYN_REPORT)
			wakeup = true;
	}

	spin_unlock(&client->buffer_lock);

	if (wakeup)
		wake_up_interruptible(&evdev->wait);
}

/*
 * Pass incoming event to all connected clients.
 * Pass incoming events to all connected clients.
 */
static void evdev_event(struct input_handle *handle,
			unsigned int type, unsigned int code, int value)
static void evdev_events(struct input_handle *handle,
			 const struct input_value *vals, unsigned int count)
{
	struct evdev *evdev = handle->private;
	struct evdev_client *client;
	struct input_event event;
	ktime_t time_mono, time_real;

	time_mono = ktime_get();
	time_real = ktime_sub(time_mono, ktime_get_monotonic_offset());

	event.type = type;
	event.code = code;
	event.value = value;

	rcu_read_lock();

	client = rcu_dereference(evdev->grab);

	if (client)
		evdev_pass_event(client, &event, time_mono, time_real);
		evdev_pass_values(client, vals, count, time_mono, time_real);
	else
		list_for_each_entry_rcu(client, &evdev->client_list, node)
			evdev_pass_event(client, &event, time_mono, time_real);
			evdev_pass_values(client, vals, count,
					  time_mono, time_real);

	rcu_read_unlock();
}

	if (type == EV_SYN && code == SYN_REPORT)
		wake_up_interruptible(&evdev->wait);
/*
 * Pass incoming event to all connected clients.
 */
static void evdev_event(struct input_handle *handle,
			unsigned int type, unsigned int code, int value)
{
	struct input_value vals[] = { { type, code, value } };

	evdev_events(handle, vals, 1);
}

static int evdev_fasync(int fd, struct file *file, int on)
@@ -653,20 +678,22 @@ static int evdev_handle_mt_request(struct input_dev *dev,
				   unsigned int size,
				   int __user *ip)
{
	const struct input_mt_slot *mt = dev->mt;
	const struct input_mt *mt = dev->mt;
	unsigned int code;
	int max_slots;
	int i;

	if (get_user(code, &ip[0]))
		return -EFAULT;
	if (!input_is_mt_value(code))
	if (!mt || !input_is_mt_value(code))
		return -EINVAL;

	max_slots = (size - sizeof(__u32)) / sizeof(__s32);
	for (i = 0; i < dev->mtsize && i < max_slots; i++)
		if (put_user(input_mt_get_value(&mt[i], code), &ip[1 + i]))
	for (i = 0; i < mt->num_slots && i < max_slots; i++) {
		int value = input_mt_get_value(&mt->slots[i], code);
		if (put_user(value, &ip[1 + i]))
			return -EFAULT;
	}

	return 0;
}
@@ -1048,6 +1075,7 @@ MODULE_DEVICE_TABLE(input, evdev_ids);

static struct input_handler evdev_handler = {
	.event		= evdev_event,
	.events		= evdev_events,
	.connect	= evdev_connect,
	.disconnect	= evdev_disconnect,
	.fops		= &evdev_fops,
Loading