Blame view

drivers/input/mouse/trackpoint.c 12.2 KB
541e316ae   Stephen Evanchik   Input: psmouse - ...
1
2
3
4
5
6
7
8
9
  /*
   * Stephen Evanchik <evanchsa@gmail.com>
   *
   * 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.
   *
   * Trademarks are the property of their respective owners.
   */
5a0e3ad6a   Tejun Heo   include cleanup: ...
10
  #include <linux/slab.h>
541e316ae   Stephen Evanchik   Input: psmouse - ...
11
12
13
  #include <linux/delay.h>
  #include <linux/serio.h>
  #include <linux/module.h>
541e316ae   Stephen Evanchik   Input: psmouse - ...
14
15
16
17
18
19
  #include <linux/input.h>
  #include <linux/libps2.h>
  #include <linux/proc_fs.h>
  #include <asm/uaccess.h>
  #include "psmouse.h"
  #include "trackpoint.h"
541e316ae   Stephen Evanchik   Input: psmouse - ...
20
  /*
0c6a61657   Shawn Nematbakhsh   Input: trackpoint...
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
   * Power-on Reset: Resets all trackpoint parameters, including RAM values,
   * to defaults.
   * Returns zero on success, non-zero on failure.
   */
  static int trackpoint_power_on_reset(struct ps2dev *ps2dev)
  {
  	unsigned char results[2];
  	int tries = 0;
  
  	/* Issue POR command, and repeat up to once if 0xFC00 received */
  	do {
  		if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) ||
  		    ps2_command(ps2dev, results, MAKE_PS2_CMD(0, 2, TP_POR)))
  			return -1;
  	} while (results[0] == 0xFC && results[1] == 0x00 && ++tries < 2);
  
  	/* Check for success response -- 0xAA00 */
  	if (results[0] != 0xAA || results[1] != 0x00)
  		return -1;
  
  	return 0;
  }
  
  /*
541e316ae   Stephen Evanchik   Input: psmouse - ...
45
46
   * Device IO: read, write and toggle bit
   */
0c6a61657   Shawn Nematbakhsh   Input: trackpoint...
47
48
  static int trackpoint_read(struct ps2dev *ps2dev,
  			   unsigned char loc, unsigned char *results)
541e316ae   Stephen Evanchik   Input: psmouse - ...
49
50
51
52
53
54
55
56
  {
  	if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) ||
  	    ps2_command(ps2dev, results, MAKE_PS2_CMD(0, 1, loc))) {
  		return -1;
  	}
  
  	return 0;
  }
0c6a61657   Shawn Nematbakhsh   Input: trackpoint...
57
58
  static int trackpoint_write(struct ps2dev *ps2dev,
  			    unsigned char loc, unsigned char val)
541e316ae   Stephen Evanchik   Input: psmouse - ...
59
60
61
62
63
64
65
66
67
68
  {
  	if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) ||
  	    ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_WRITE_MEM)) ||
  	    ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, loc)) ||
  	    ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, val))) {
  		return -1;
  	}
  
  	return 0;
  }
0c6a61657   Shawn Nematbakhsh   Input: trackpoint...
69
70
  static int trackpoint_toggle_bit(struct ps2dev *ps2dev,
  				 unsigned char loc, unsigned char mask)
541e316ae   Stephen Evanchik   Input: psmouse - ...
71
72
73
74
75
76
77
78
79
80
81
82
83
84
  {
  	/* Bad things will happen if the loc param isn't in this range */
  	if (loc < 0x20 || loc >= 0x2F)
  		return -1;
  
  	if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) ||
  	    ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_TOGGLE)) ||
  	    ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, loc)) ||
  	    ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, mask))) {
  		return -1;
  	}
  
  	return 0;
  }
0c6a61657   Shawn Nematbakhsh   Input: trackpoint...
85
86
87
88
89
90
91
92
93
94
95
96
  static int trackpoint_update_bit(struct ps2dev *ps2dev, unsigned char loc,
  				 unsigned char mask, unsigned char value)
  {
  	int retval = 0;
  	unsigned char data;
  
  	trackpoint_read(ps2dev, loc, &data);
  	if (((data & mask) == mask) != !!value)
  		retval = trackpoint_toggle_bit(ps2dev, loc, mask);
  
  	return retval;
  }
541e316ae   Stephen Evanchik   Input: psmouse - ...
97

cfe9e8886   Dmitry Torokhov   Input: rework psm...
98
99
100
101
102
103
104
  /*
   * Trackpoint-specific attributes
   */
  struct trackpoint_attr_data {
  	size_t field_offset;
  	unsigned char command;
  	unsigned char mask;
b8044c74b   Dmitry Torokhov   Input: trackpoint...
105
  	unsigned char inverted;
0c6a61657   Shawn Nematbakhsh   Input: trackpoint...
106
  	unsigned char power_on_default;
cfe9e8886   Dmitry Torokhov   Input: rework psm...
107
  };
541e316ae   Stephen Evanchik   Input: psmouse - ...
108

cfe9e8886   Dmitry Torokhov   Input: rework psm...
109
110
111
112
  static ssize_t trackpoint_show_int_attr(struct psmouse *psmouse, void *data, char *buf)
  {
  	struct trackpoint_data *tp = psmouse->private;
  	struct trackpoint_attr_data *attr = data;
b8044c74b   Dmitry Torokhov   Input: trackpoint...
113
114
115
116
  	unsigned char value = *(unsigned char *)((char *)tp + attr->field_offset);
  
  	if (attr->inverted)
  		value = !value;
541e316ae   Stephen Evanchik   Input: psmouse - ...
117

b8044c74b   Dmitry Torokhov   Input: trackpoint...
118
119
  	return sprintf(buf, "%u
  ", value);
cfe9e8886   Dmitry Torokhov   Input: rework psm...
120
  }
541e316ae   Stephen Evanchik   Input: psmouse - ...
121

cfe9e8886   Dmitry Torokhov   Input: rework psm...
122
123
124
125
126
127
  static ssize_t trackpoint_set_int_attr(struct psmouse *psmouse, void *data,
  					const char *buf, size_t count)
  {
  	struct trackpoint_data *tp = psmouse->private;
  	struct trackpoint_attr_data *attr = data;
  	unsigned char *field = (unsigned char *)((char *)tp + attr->field_offset);
76496e7a0   JJ Ding   Input: convert ob...
128
129
  	unsigned char value;
  	int err;
541e316ae   Stephen Evanchik   Input: psmouse - ...
130

76496e7a0   JJ Ding   Input: convert ob...
131
132
133
  	err = kstrtou8(buf, 10, &value);
  	if (err)
  		return err;
541e316ae   Stephen Evanchik   Input: psmouse - ...
134

cfe9e8886   Dmitry Torokhov   Input: rework psm...
135
136
  	*field = value;
  	trackpoint_write(&psmouse->ps2dev, attr->command, value);
541e316ae   Stephen Evanchik   Input: psmouse - ...
137

cfe9e8886   Dmitry Torokhov   Input: rework psm...
138
139
  	return count;
  }
541e316ae   Stephen Evanchik   Input: psmouse - ...
140

0c6a61657   Shawn Nematbakhsh   Input: trackpoint...
141
  #define TRACKPOINT_INT_ATTR(_name, _command, _default)				\
cfe9e8886   Dmitry Torokhov   Input: rework psm...
142
143
144
  	static struct trackpoint_attr_data trackpoint_attr_##_name = {		\
  		.field_offset = offsetof(struct trackpoint_data, _name),	\
  		.command = _command,						\
0c6a61657   Shawn Nematbakhsh   Input: trackpoint...
145
  		.power_on_default = _default,					\
cfe9e8886   Dmitry Torokhov   Input: rework psm...
146
147
148
149
150
151
152
153
154
155
156
  	};									\
  	PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO,				\
  			    &trackpoint_attr_##_name,				\
  			    trackpoint_show_int_attr, trackpoint_set_int_attr)
  
  static ssize_t trackpoint_set_bit_attr(struct psmouse *psmouse, void *data,
  					const char *buf, size_t count)
  {
  	struct trackpoint_data *tp = psmouse->private;
  	struct trackpoint_attr_data *attr = data;
  	unsigned char *field = (unsigned char *)((char *)tp + attr->field_offset);
76496e7a0   JJ Ding   Input: convert ob...
157
158
159
160
161
162
  	unsigned int value;
  	int err;
  
  	err = kstrtouint(buf, 10, &value);
  	if (err)
  		return err;
cfe9e8886   Dmitry Torokhov   Input: rework psm...
163

76496e7a0   JJ Ding   Input: convert ob...
164
  	if (value > 1)
cfe9e8886   Dmitry Torokhov   Input: rework psm...
165
  		return -EINVAL;
b8044c74b   Dmitry Torokhov   Input: trackpoint...
166
167
  	if (attr->inverted)
  		value = !value;
cfe9e8886   Dmitry Torokhov   Input: rework psm...
168
169
170
171
  	if (*field != value) {
  		*field = value;
  		trackpoint_toggle_bit(&psmouse->ps2dev, attr->command, attr->mask);
  	}
541e316ae   Stephen Evanchik   Input: psmouse - ...
172

cfe9e8886   Dmitry Torokhov   Input: rework psm...
173
174
  	return count;
  }
541e316ae   Stephen Evanchik   Input: psmouse - ...
175

541e316ae   Stephen Evanchik   Input: psmouse - ...
176

0c6a61657   Shawn Nematbakhsh   Input: trackpoint...
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
  #define TRACKPOINT_BIT_ATTR(_name, _command, _mask, _inv, _default)	\
  static struct trackpoint_attr_data trackpoint_attr_##_name = {		\
  	.field_offset		= offsetof(struct trackpoint_data,	\
  					   _name),			\
  	.command		= _command,				\
  	.mask			= _mask,				\
  	.inverted		= _inv,					\
  	.power_on_default	= _default,				\
  	};								\
  PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO,				\
  		    &trackpoint_attr_##_name,				\
  		    trackpoint_show_int_attr, trackpoint_set_bit_attr)
  
  #define TRACKPOINT_UPDATE_BIT(_psmouse, _tp, _name)			\
  do {									\
  	struct trackpoint_attr_data *_attr = &trackpoint_attr_##_name;	\
  									\
  	trackpoint_update_bit(&_psmouse->ps2dev,			\
  			_attr->command, _attr->mask, _tp->_name);	\
  } while (0)
  
  #define TRACKPOINT_UPDATE(_power_on, _psmouse, _tp, _name)		\
  do {									\
  	if (!_power_on ||						\
  	    _tp->_name != trackpoint_attr_##_name.power_on_default) {	\
  		if (!trackpoint_attr_##_name.mask)			\
  			trackpoint_write(&_psmouse->ps2dev,		\
  				 trackpoint_attr_##_name.command,	\
  				 _tp->_name);				\
  		else							\
  			TRACKPOINT_UPDATE_BIT(_psmouse, _tp, _name);	\
  	}								\
  } while (0)
  
  #define TRACKPOINT_SET_POWER_ON_DEFAULT(_tp, _name)				\
  	(_tp->_name = trackpoint_attr_##_name.power_on_default)
  
  TRACKPOINT_INT_ATTR(sensitivity, TP_SENS, TP_DEF_SENS);
  TRACKPOINT_INT_ATTR(speed, TP_SPEED, TP_DEF_SPEED);
  TRACKPOINT_INT_ATTR(inertia, TP_INERTIA, TP_DEF_INERTIA);
  TRACKPOINT_INT_ATTR(reach, TP_REACH, TP_DEF_REACH);
  TRACKPOINT_INT_ATTR(draghys, TP_DRAGHYS, TP_DEF_DRAGHYS);
  TRACKPOINT_INT_ATTR(mindrag, TP_MINDRAG, TP_DEF_MINDRAG);
  TRACKPOINT_INT_ATTR(thresh, TP_THRESH, TP_DEF_THRESH);
  TRACKPOINT_INT_ATTR(upthresh, TP_UP_THRESH, TP_DEF_UP_THRESH);
  TRACKPOINT_INT_ATTR(ztime, TP_Z_TIME, TP_DEF_Z_TIME);
  TRACKPOINT_INT_ATTR(jenks, TP_JENKS_CURV, TP_DEF_JENKS_CURV);
2ba353204   haarp   Input: psmouse - ...
224
  TRACKPOINT_INT_ATTR(drift_time, TP_DRIFT_TIME, TP_DEF_DRIFT_TIME);
0c6a61657   Shawn Nematbakhsh   Input: trackpoint...
225
226
227
228
229
230
231
  
  TRACKPOINT_BIT_ATTR(press_to_select, TP_TOGGLE_PTSON, TP_MASK_PTSON, 0,
  		    TP_DEF_PTSON);
  TRACKPOINT_BIT_ATTR(skipback, TP_TOGGLE_SKIPBACK, TP_MASK_SKIPBACK, 0,
  		    TP_DEF_SKIPBACK);
  TRACKPOINT_BIT_ATTR(ext_dev, TP_TOGGLE_EXT_DEV, TP_MASK_EXT_DEV, 1,
  		    TP_DEF_EXT_DEV);
541e316ae   Stephen Evanchik   Input: psmouse - ...
232
233
  
  static struct attribute *trackpoint_attrs[] = {
cfe9e8886   Dmitry Torokhov   Input: rework psm...
234
235
236
237
238
239
240
241
242
243
  	&psmouse_attr_sensitivity.dattr.attr,
  	&psmouse_attr_speed.dattr.attr,
  	&psmouse_attr_inertia.dattr.attr,
  	&psmouse_attr_reach.dattr.attr,
  	&psmouse_attr_draghys.dattr.attr,
  	&psmouse_attr_mindrag.dattr.attr,
  	&psmouse_attr_thresh.dattr.attr,
  	&psmouse_attr_upthresh.dattr.attr,
  	&psmouse_attr_ztime.dattr.attr,
  	&psmouse_attr_jenks.dattr.attr,
2ba353204   haarp   Input: psmouse - ...
244
  	&psmouse_attr_drift_time.dattr.attr,
cfe9e8886   Dmitry Torokhov   Input: rework psm...
245
246
247
  	&psmouse_attr_press_to_select.dattr.attr,
  	&psmouse_attr_skipback.dattr.attr,
  	&psmouse_attr_ext_dev.dattr.attr,
541e316ae   Stephen Evanchik   Input: psmouse - ...
248
249
250
251
252
253
  	NULL
  };
  
  static struct attribute_group trackpoint_attr_group = {
  	.attrs = trackpoint_attrs,
  };
184dd2751   Dmitry Torokhov   Input: trackpoint...
254
  static int trackpoint_start_protocol(struct psmouse *psmouse, unsigned char *firmware_id)
541e316ae   Stephen Evanchik   Input: psmouse - ...
255
  {
184dd2751   Dmitry Torokhov   Input: trackpoint...
256
  	unsigned char param[2] = { 0 };
541e316ae   Stephen Evanchik   Input: psmouse - ...
257

184dd2751   Dmitry Torokhov   Input: trackpoint...
258
259
260
261
262
263
264
265
266
267
  	if (ps2_command(&psmouse->ps2dev, param, MAKE_PS2_CMD(0, 2, TP_READ_ID)))
  		return -1;
  
  	if (param[0] != TP_MAGIC_IDENT)
  		return -1;
  
  	if (firmware_id)
  		*firmware_id = param[1];
  
  	return 0;
541e316ae   Stephen Evanchik   Input: psmouse - ...
268
  }
0c6a61657   Shawn Nematbakhsh   Input: trackpoint...
269
270
271
272
273
274
275
  /*
   * Write parameters to trackpad.
   * in_power_on_state: Set to true if TP is in default / power-on state (ex. if
   *		      power-on reset was run). If so, values will only be
   *		      written to TP if they differ from power-on default.
   */
  static int trackpoint_sync(struct psmouse *psmouse, bool in_power_on_state)
541e316ae   Stephen Evanchik   Input: psmouse - ...
276
  {
541e316ae   Stephen Evanchik   Input: psmouse - ...
277
  	struct trackpoint_data *tp = psmouse->private;
541e316ae   Stephen Evanchik   Input: psmouse - ...
278

0c6a61657   Shawn Nematbakhsh   Input: trackpoint...
279
280
281
282
283
284
285
  	if (!in_power_on_state) {
  		/*
  		 * Disable features that may make device unusable
  		 * with this driver.
  		 */
  		trackpoint_update_bit(&psmouse->ps2dev, TP_TOGGLE_TWOHAND,
  				      TP_MASK_TWOHAND, TP_DEF_TWOHAND);
541e316ae   Stephen Evanchik   Input: psmouse - ...
286

0c6a61657   Shawn Nematbakhsh   Input: trackpoint...
287
288
  		trackpoint_update_bit(&psmouse->ps2dev, TP_TOGGLE_SOURCE_TAG,
  				      TP_MASK_SOURCE_TAG, TP_DEF_SOURCE_TAG);
541e316ae   Stephen Evanchik   Input: psmouse - ...
289

0c6a61657   Shawn Nematbakhsh   Input: trackpoint...
290
291
292
  		trackpoint_update_bit(&psmouse->ps2dev, TP_TOGGLE_MB,
  				      TP_MASK_MB, TP_DEF_MB);
  	}
541e316ae   Stephen Evanchik   Input: psmouse - ...
293

0c6a61657   Shawn Nematbakhsh   Input: trackpoint...
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
  	/*
  	 * These properties can be changed in this driver. Only
  	 * configure them if the values are non-default or if the TP is in
  	 * an unknown state.
  	 */
  	TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, sensitivity);
  	TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, inertia);
  	TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, speed);
  	TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, reach);
  	TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, draghys);
  	TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, mindrag);
  	TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, thresh);
  	TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, upthresh);
  	TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, ztime);
  	TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, jenks);
2ba353204   haarp   Input: psmouse - ...
309
  	TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, drift_time);
0c6a61657   Shawn Nematbakhsh   Input: trackpoint...
310
311
312
313
314
  
  	/* toggles */
  	TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, press_to_select);
  	TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, skipback);
  	TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, ext_dev);
541e316ae   Stephen Evanchik   Input: psmouse - ...
315
316
317
318
319
320
  
  	return 0;
  }
  
  static void trackpoint_defaults(struct trackpoint_data *tp)
  {
0c6a61657   Shawn Nematbakhsh   Input: trackpoint...
321
322
323
324
325
326
327
328
329
  	TRACKPOINT_SET_POWER_ON_DEFAULT(tp, sensitivity);
  	TRACKPOINT_SET_POWER_ON_DEFAULT(tp, speed);
  	TRACKPOINT_SET_POWER_ON_DEFAULT(tp, reach);
  	TRACKPOINT_SET_POWER_ON_DEFAULT(tp, draghys);
  	TRACKPOINT_SET_POWER_ON_DEFAULT(tp, mindrag);
  	TRACKPOINT_SET_POWER_ON_DEFAULT(tp, thresh);
  	TRACKPOINT_SET_POWER_ON_DEFAULT(tp, upthresh);
  	TRACKPOINT_SET_POWER_ON_DEFAULT(tp, ztime);
  	TRACKPOINT_SET_POWER_ON_DEFAULT(tp, jenks);
2ba353204   haarp   Input: psmouse - ...
330
  	TRACKPOINT_SET_POWER_ON_DEFAULT(tp, drift_time);
0c6a61657   Shawn Nematbakhsh   Input: trackpoint...
331
332
333
334
335
336
  	TRACKPOINT_SET_POWER_ON_DEFAULT(tp, inertia);
  
  	/* toggles */
  	TRACKPOINT_SET_POWER_ON_DEFAULT(tp, press_to_select);
  	TRACKPOINT_SET_POWER_ON_DEFAULT(tp, skipback);
  	TRACKPOINT_SET_POWER_ON_DEFAULT(tp, ext_dev);
541e316ae   Stephen Evanchik   Input: psmouse - ...
337
  }
184dd2751   Dmitry Torokhov   Input: trackpoint...
338
339
340
341
342
343
344
345
346
347
  static void trackpoint_disconnect(struct psmouse *psmouse)
  {
  	sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj, &trackpoint_attr_group);
  
  	kfree(psmouse->private);
  	psmouse->private = NULL;
  }
  
  static int trackpoint_reconnect(struct psmouse *psmouse)
  {
0c6a61657   Shawn Nematbakhsh   Input: trackpoint...
348
  	int reset_fail;
184dd2751   Dmitry Torokhov   Input: trackpoint...
349
350
  	if (trackpoint_start_protocol(psmouse, NULL))
  		return -1;
0c6a61657   Shawn Nematbakhsh   Input: trackpoint...
351
352
  	reset_fail = trackpoint_power_on_reset(&psmouse->ps2dev);
  	if (trackpoint_sync(psmouse, !reset_fail))
184dd2751   Dmitry Torokhov   Input: trackpoint...
353
354
355
356
  		return -1;
  
  	return 0;
  }
b7802c5c1   Dmitry Torokhov   Input: psmouse - ...
357
  int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
541e316ae   Stephen Evanchik   Input: psmouse - ...
358
  {
541e316ae   Stephen Evanchik   Input: psmouse - ...
359
360
361
  	struct ps2dev *ps2dev = &psmouse->ps2dev;
  	unsigned char firmware_id;
  	unsigned char button_info;
8ff22ea7d   Jeff Garzik   Input: trackpoint...
362
  	int error;
541e316ae   Stephen Evanchik   Input: psmouse - ...
363

184dd2751   Dmitry Torokhov   Input: trackpoint...
364
  	if (trackpoint_start_protocol(psmouse, &firmware_id))
541e316ae   Stephen Evanchik   Input: psmouse - ...
365
366
367
368
  		return -1;
  
  	if (!set_properties)
  		return 0;
541e316ae   Stephen Evanchik   Input: psmouse - ...
369
  	if (trackpoint_read(&psmouse->ps2dev, TP_EXT_BTN, &button_info)) {
fb16395ee   JJ Ding   Input: trackpoint...
370
371
  		psmouse_warn(psmouse, "failed to get extended button data
  ");
541e316ae   Stephen Evanchik   Input: psmouse - ...
372
373
  		button_info = 0;
  	}
315eb996d   Dmitry Torokhov   Input: psmouse - ...
374
375
  	psmouse->private = kzalloc(sizeof(struct trackpoint_data), GFP_KERNEL);
  	if (!psmouse->private)
6792cbbb2   Davidlohr Bueso   Input: return -EN...
376
  		return -ENOMEM;
541e316ae   Stephen Evanchik   Input: psmouse - ...
377
378
379
  
  	psmouse->vendor = "IBM";
  	psmouse->name = "TrackPoint";
184dd2751   Dmitry Torokhov   Input: trackpoint...
380
  	psmouse->reconnect = trackpoint_reconnect;
541e316ae   Stephen Evanchik   Input: psmouse - ...
381
  	psmouse->disconnect = trackpoint_disconnect;
315eb996d   Dmitry Torokhov   Input: psmouse - ...
382
383
  	if ((button_info & 0x0f) >= 3)
  		__set_bit(BTN_MIDDLE, psmouse->dev->keybit);
01d4cd5c4   Hans de Goede   Input: add missin...
384
  	__set_bit(INPUT_PROP_POINTER, psmouse->dev->propbit);
7611392fe   Hans de Goede   Input: add INPUT_...
385
  	__set_bit(INPUT_PROP_POINTING_STICK, psmouse->dev->propbit);
315eb996d   Dmitry Torokhov   Input: psmouse - ...
386
  	trackpoint_defaults(psmouse->private);
0c6a61657   Shawn Nematbakhsh   Input: trackpoint...
387
388
389
390
391
392
  
  	error = trackpoint_power_on_reset(&psmouse->ps2dev);
  
  	/* Write defaults to TP only if reset fails. */
  	if (error)
  		trackpoint_sync(psmouse, false);
541e316ae   Stephen Evanchik   Input: psmouse - ...
393

8ff22ea7d   Jeff Garzik   Input: trackpoint...
394
395
  	error = sysfs_create_group(&ps2dev->serio->dev.kobj, &trackpoint_attr_group);
  	if (error) {
fb16395ee   JJ Ding   Input: trackpoint...
396
397
398
399
  		psmouse_err(psmouse,
  			    "failed to create sysfs attributes, error: %d
  ",
  			    error);
315eb996d   Dmitry Torokhov   Input: psmouse - ...
400
401
  		kfree(psmouse->private);
  		psmouse->private = NULL;
8ff22ea7d   Jeff Garzik   Input: trackpoint...
402
403
  		return -1;
  	}
541e316ae   Stephen Evanchik   Input: psmouse - ...
404

fb16395ee   JJ Ding   Input: trackpoint...
405
406
407
408
409
  	psmouse_info(psmouse,
  		     "IBM TrackPoint firmware: 0x%02x, buttons: %d/%d
  ",
  		     firmware_id,
  		     (button_info & 0xf0) >> 4, button_info & 0x0f);
541e316ae   Stephen Evanchik   Input: psmouse - ...
410
411
412
  
  	return 0;
  }