Blame view

drivers/input/input-mt.c 5.07 KB
47c78e891   Henrik Rydberg   input: mt: Break ...
1
2
3
4
5
6
7
8
9
10
11
  /*
   * Input Multitouch Library
   *
   * Copyright (c) 2008-2010 Henrik Rydberg
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 as published by
   * the Free Software Foundation.
   */
  
  #include <linux/input/mt.h>
15d0580f2   Paul Gortmaker   drivers/input: ad...
12
  #include <linux/export.h>
47c78e891   Henrik Rydberg   input: mt: Break ...
13
  #include <linux/slab.h>
c5f4dec1c   Henrik Rydberg   input: mt: Move t...
14
  #define TRKID_SGN	((TRKID_MAX + 1) >> 1)
47c78e891   Henrik Rydberg   input: mt: Break ...
15
  /**
8cde81001   Henrik Rydberg   input: mt: Collec...
16
   * input_mt_init_slots() - initialize MT input slots
47c78e891   Henrik Rydberg   input: mt: Break ...
17
18
19
   * @dev: input device supporting MT events and finger tracking
   * @num_slots: number of slots used by the device
   *
8cde81001   Henrik Rydberg   input: mt: Collec...
20
   * This function allocates all necessary memory for MT slot handling
c5f4dec1c   Henrik Rydberg   input: mt: Move t...
21
22
23
24
   * in the input device, prepares the ABS_MT_SLOT and
   * ABS_MT_TRACKING_ID events for use and sets up appropriate buffers.
   * May be called repeatedly. Returns -EINVAL if attempting to
   * reinitialize with a different number of slots.
47c78e891   Henrik Rydberg   input: mt: Break ...
25
   */
8cde81001   Henrik Rydberg   input: mt: Collec...
26
  int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots)
47c78e891   Henrik Rydberg   input: mt: Break ...
27
28
29
30
31
  {
  	int i;
  
  	if (!num_slots)
  		return 0;
8cde81001   Henrik Rydberg   input: mt: Collec...
32
33
  	if (dev->mt)
  		return dev->mtsize != num_slots ? -EINVAL : 0;
47c78e891   Henrik Rydberg   input: mt: Break ...
34
35
36
37
38
39
40
  
  	dev->mt = kcalloc(num_slots, sizeof(struct input_mt_slot), GFP_KERNEL);
  	if (!dev->mt)
  		return -ENOMEM;
  
  	dev->mtsize = num_slots;
  	input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0);
c5f4dec1c   Henrik Rydberg   input: mt: Move t...
41
  	input_set_abs_params(dev, ABS_MT_TRACKING_ID, 0, TRKID_MAX, 0, 0);
8cde81001   Henrik Rydberg   input: mt: Collec...
42
  	input_set_events_per_packet(dev, 6 * num_slots);
47c78e891   Henrik Rydberg   input: mt: Break ...
43
44
45
46
47
48
49
  
  	/* Mark slots as 'unused' */
  	for (i = 0; i < num_slots; i++)
  		input_mt_set_value(&dev->mt[i], ABS_MT_TRACKING_ID, -1);
  
  	return 0;
  }
8cde81001   Henrik Rydberg   input: mt: Collec...
50
  EXPORT_SYMBOL(input_mt_init_slots);
47c78e891   Henrik Rydberg   input: mt: Break ...
51
52
53
54
55
56
57
58
59
60
61
62
63
  
  /**
   * input_mt_destroy_slots() - frees the MT slots of the input device
   * @dev: input device with allocated MT slots
   *
   * This function is only needed in error path as the input core will
   * automatically free the MT slots when the device is destroyed.
   */
  void input_mt_destroy_slots(struct input_dev *dev)
  {
  	kfree(dev->mt);
  	dev->mt = NULL;
  	dev->mtsize = 0;
8cde81001   Henrik Rydberg   input: mt: Collec...
64
  	dev->slot = 0;
c5f4dec1c   Henrik Rydberg   input: mt: Move t...
65
  	dev->trkid = 0;
47c78e891   Henrik Rydberg   input: mt: Break ...
66
67
  }
  EXPORT_SYMBOL(input_mt_destroy_slots);
c5f4dec1c   Henrik Rydberg   input: mt: Move t...
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
  
  /**
   * input_mt_report_slot_state() - report contact state
   * @dev: input device with allocated MT slots
   * @tool_type: the tool type to use in this slot
   * @active: true if contact is active, false otherwise
   *
   * Reports a contact via ABS_MT_TRACKING_ID, and optionally
   * ABS_MT_TOOL_TYPE. If active is true and the slot is currently
   * inactive, or if the tool type is changed, a new tracking id is
   * assigned to the slot. The tool type is only reported if the
   * corresponding absbit field is set.
   */
  void input_mt_report_slot_state(struct input_dev *dev,
  				unsigned int tool_type, bool active)
  {
  	struct input_mt_slot *mt;
  	int id;
  
  	if (!dev->mt || !active) {
  		input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
  		return;
  	}
  
  	mt = &dev->mt[dev->slot];
  	id = input_mt_get_value(mt, ABS_MT_TRACKING_ID);
  	if (id < 0 || input_mt_get_value(mt, ABS_MT_TOOL_TYPE) != tool_type)
  		id = input_mt_new_trkid(dev);
  
  	input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id);
  	input_event(dev, EV_ABS, ABS_MT_TOOL_TYPE, tool_type);
  }
  EXPORT_SYMBOL(input_mt_report_slot_state);
  
  /**
   * input_mt_report_finger_count() - report contact count
   * @dev: input device with allocated MT slots
   * @count: the number of contacts
   *
   * Reports the contact count via BTN_TOOL_FINGER, BTN_TOOL_DOUBLETAP,
   * BTN_TOOL_TRIPLETAP and BTN_TOOL_QUADTAP.
   *
   * The input core ensures only the KEY events already setup for
   * this device will produce output.
   */
  void input_mt_report_finger_count(struct input_dev *dev, int count)
  {
  	input_event(dev, EV_KEY, BTN_TOOL_FINGER, count == 1);
  	input_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, count == 2);
  	input_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, count == 3);
  	input_event(dev, EV_KEY, BTN_TOOL_QUADTAP, count == 4);
d5051272f   Daniel Kurtz   Input: add BTN_TO...
119
  	input_event(dev, EV_KEY, BTN_TOOL_QUINTTAP, count == 5);
c5f4dec1c   Henrik Rydberg   input: mt: Move t...
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
  }
  EXPORT_SYMBOL(input_mt_report_finger_count);
  
  /**
   * input_mt_report_pointer_emulation() - common pointer emulation
   * @dev: input device with allocated MT slots
   * @use_count: report number of active contacts as finger count
   *
   * Performs legacy pointer emulation via BTN_TOUCH, ABS_X, ABS_Y and
   * ABS_PRESSURE. Touchpad finger count is emulated if use_count is true.
   *
   * The input core ensures only the KEY and ABS axes already setup for
   * this device will produce output.
   */
  void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
  {
  	struct input_mt_slot *oldest = 0;
  	int oldid = dev->trkid;
  	int count = 0;
  	int i;
  
  	for (i = 0; i < dev->mtsize; ++i) {
  		struct input_mt_slot *ps = &dev->mt[i];
  		int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID);
  
  		if (id < 0)
  			continue;
  		if ((id - oldid) & TRKID_SGN) {
  			oldest = ps;
  			oldid = id;
  		}
  		count++;
  	}
  
  	input_event(dev, EV_KEY, BTN_TOUCH, count > 0);
  	if (use_count)
  		input_mt_report_finger_count(dev, count);
  
  	if (oldest) {
  		int x = input_mt_get_value(oldest, ABS_MT_POSITION_X);
  		int y = input_mt_get_value(oldest, ABS_MT_POSITION_Y);
  		int p = input_mt_get_value(oldest, ABS_MT_PRESSURE);
  
  		input_event(dev, EV_ABS, ABS_X, x);
  		input_event(dev, EV_ABS, ABS_Y, y);
  		input_event(dev, EV_ABS, ABS_PRESSURE, p);
  	} else {
  		input_event(dev, EV_ABS, ABS_PRESSURE, 0);
  	}
  }
  EXPORT_SYMBOL(input_mt_report_pointer_emulation);