Blame view

drivers/input/joydev.c 22.6 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
  /*
   * Joystick device driver for the input driver suite.
   *
   * Copyright (c) 1999-2002 Vojtech Pavlik
   * Copyright (c) 1999 Colin Van Dyke
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   */
da0c49011   Joe Perches   Input: use pr_fmt...
12
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
14
15
16
17
18
19
20
  #include <asm/io.h>
  #include <asm/system.h>
  #include <linux/delay.h>
  #include <linux/errno.h>
  #include <linux/joystick.h>
  #include <linux/input.h>
  #include <linux/kernel.h>
  #include <linux/major.h>
a99bbaf5e   Alexey Dobriyan   headers: remove s...
21
  #include <linux/sched.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
24
25
26
27
  #include <linux/slab.h>
  #include <linux/mm.h>
  #include <linux/miscdevice.h>
  #include <linux/module.h>
  #include <linux/poll.h>
  #include <linux/init.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
  #include <linux/device.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
31
32
33
34
35
36
37
  
  MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
  MODULE_DESCRIPTION("Joystick device interfaces");
  MODULE_SUPPORTED_DEVICE("input/js");
  MODULE_LICENSE("GPL");
  
  #define JOYDEV_MINOR_BASE	0
  #define JOYDEV_MINORS		16
  #define JOYDEV_BUFFER_SIZE	64
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
  struct joydev {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
  	int open;
  	int minor;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
  	struct input_handle handle;
  	wait_queue_head_t wait;
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
43
  	struct list_head client_list;
b126207cc   Dmitry Torokhov   Input: joydev - i...
44
45
  	spinlock_t client_lock; /* protects client_list */
  	struct mutex mutex;
9657d75c5   Dmitry Torokhov   Input: convert fr...
46
  	struct device dev;
20da92de8   Dmitry Torokhov   Input: change inp...
47
  	bool exist;
9657d75c5   Dmitry Torokhov   Input: convert fr...
48

81c2a3ba4   Daniel Mack   Input: use ABS_CN...
49
  	struct js_corr corr[ABS_CNT];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
51
52
53
54
  	struct JS_DATA_SAVE_TYPE glue;
  	int nabs;
  	int nkey;
  	__u16 keymap[KEY_MAX - BTN_MISC + 1];
  	__u16 keypam[KEY_MAX - BTN_MISC + 1];
81c2a3ba4   Daniel Mack   Input: use ABS_CN...
55
56
57
  	__u8 absmap[ABS_CNT];
  	__u8 abspam[ABS_CNT];
  	__s16 abs[ABS_CNT];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
  };
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
59
  struct joydev_client {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
61
62
63
  	struct js_event buffer[JOYDEV_BUFFER_SIZE];
  	int head;
  	int tail;
  	int startup;
b126207cc   Dmitry Torokhov   Input: joydev - i...
64
  	spinlock_t buffer_lock; /* protects access to buffer, head and tail */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
66
67
68
69
70
  	struct fasync_struct *fasync;
  	struct joydev *joydev;
  	struct list_head node;
  };
  
  static struct joydev *joydev_table[JOYDEV_MINORS];
b126207cc   Dmitry Torokhov   Input: joydev - i...
71
  static DEFINE_MUTEX(joydev_table_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
74
75
  
  static int joydev_correct(int value, struct js_corr *corr)
  {
  	switch (corr->type) {
b126207cc   Dmitry Torokhov   Input: joydev - i...
76
77
78
79
80
81
82
83
84
85
86
87
  
  	case JS_CORR_NONE:
  		break;
  
  	case JS_CORR_BROKEN:
  		value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 :
  			((corr->coef[3] * (value - corr->coef[1])) >> 14)) :
  			((corr->coef[2] * (value - corr->coef[0])) >> 14);
  		break;
  
  	default:
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
  	}
1e0afb288   Dmitry Torokhov   Input: fix format...
89
  	return value < -32767 ? -32767 : (value > 32767 ? 32767 : value);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
  }
b126207cc   Dmitry Torokhov   Input: joydev - i...
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
  static void joydev_pass_event(struct joydev_client *client,
  			      struct js_event *event)
  {
  	struct joydev *joydev = client->joydev;
  
  	/*
  	 * IRQs already disabled, just acquire the lock
  	 */
  	spin_lock(&client->buffer_lock);
  
  	client->buffer[client->head] = *event;
  
  	if (client->startup == joydev->nabs + joydev->nkey) {
  		client->head++;
  		client->head &= JOYDEV_BUFFER_SIZE - 1;
  		if (client->tail == client->head)
  			client->startup = 0;
  	}
  
  	spin_unlock(&client->buffer_lock);
  
  	kill_fasync(&client->fasync, SIGIO, POLL_IN);
  }
  
  static void joydev_event(struct input_handle *handle,
  			 unsigned int type, unsigned int code, int value)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
118
  {
  	struct joydev *joydev = handle->private;
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
119
  	struct joydev_client *client;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
121
122
  	struct js_event event;
  
  	switch (type) {
b126207cc   Dmitry Torokhov   Input: joydev - i...
123
124
125
126
127
128
129
  	case EV_KEY:
  		if (code < BTN_MISC || value == 2)
  			return;
  		event.type = JS_EVENT_BUTTON;
  		event.number = joydev->keymap[code - BTN_MISC];
  		event.value = value;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130

b126207cc   Dmitry Torokhov   Input: joydev - i...
131
132
133
134
135
136
  	case EV_ABS:
  		event.type = JS_EVENT_AXIS;
  		event.number = joydev->absmap[code];
  		event.value = joydev_correct(value,
  					&joydev->corr[event.number]);
  		if (event.value == joydev->abs[event.number])
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
  			return;
b126207cc   Dmitry Torokhov   Input: joydev - i...
138
139
140
141
142
  		joydev->abs[event.number] = event.value;
  		break;
  
  	default:
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
  	}
6f5eacfc1   Tobias Klauser   Input: joydev - r...
144
  	event.time = jiffies_to_msecs(jiffies);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145

82ba56c27   Dmitry Torokhov   Input: use full R...
146
  	rcu_read_lock();
b126207cc   Dmitry Torokhov   Input: joydev - i...
147
148
  	list_for_each_entry_rcu(client, &joydev->client_list, node)
  		joydev_pass_event(client, &event);
82ba56c27   Dmitry Torokhov   Input: use full R...
149
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
151
152
153
154
155
  
  	wake_up_interruptible(&joydev->wait);
  }
  
  static int joydev_fasync(int fd, struct file *file, int on)
  {
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
156
  	struct joydev_client *client = file->private_data;
1e0afb288   Dmitry Torokhov   Input: fix format...
157

60aa49243   Jonathan Corbet   Rationalize fasyn...
158
  	return fasync_helper(fd, file, on, &client->fasync);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
  }
9657d75c5   Dmitry Torokhov   Input: convert fr...
160
  static void joydev_free(struct device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
  {
9657d75c5   Dmitry Torokhov   Input: convert fr...
162
  	struct joydev *joydev = container_of(dev, struct joydev, dev);
a7097ff89   Dmitry Torokhov   Input: make sure ...
163
  	input_put_device(joydev->handle.dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
165
  	kfree(joydev);
  }
b126207cc   Dmitry Torokhov   Input: joydev - i...
166
167
168
169
170
171
  static void joydev_attach_client(struct joydev *joydev,
  				 struct joydev_client *client)
  {
  	spin_lock(&joydev->client_lock);
  	list_add_tail_rcu(&client->node, &joydev->client_list);
  	spin_unlock(&joydev->client_lock);
b126207cc   Dmitry Torokhov   Input: joydev - i...
172
173
174
175
176
177
178
179
  }
  
  static void joydev_detach_client(struct joydev *joydev,
  				 struct joydev_client *client)
  {
  	spin_lock(&joydev->client_lock);
  	list_del_rcu(&client->node);
  	spin_unlock(&joydev->client_lock);
82ba56c27   Dmitry Torokhov   Input: use full R...
180
  	synchronize_rcu();
b126207cc   Dmitry Torokhov   Input: joydev - i...
181
182
183
184
185
186
187
188
189
190
191
192
  }
  
  static int joydev_open_device(struct joydev *joydev)
  {
  	int retval;
  
  	retval = mutex_lock_interruptible(&joydev->mutex);
  	if (retval)
  		return retval;
  
  	if (!joydev->exist)
  		retval = -ENODEV;
064450140   Oliver Neukum   Input: fix open c...
193
  	else if (!joydev->open++) {
b126207cc   Dmitry Torokhov   Input: joydev - i...
194
  		retval = input_open_device(&joydev->handle);
064450140   Oliver Neukum   Input: fix open c...
195
196
197
  		if (retval)
  			joydev->open--;
  	}
b126207cc   Dmitry Torokhov   Input: joydev - i...
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
224
225
226
227
  
  	mutex_unlock(&joydev->mutex);
  	return retval;
  }
  
  static void joydev_close_device(struct joydev *joydev)
  {
  	mutex_lock(&joydev->mutex);
  
  	if (joydev->exist && !--joydev->open)
  		input_close_device(&joydev->handle);
  
  	mutex_unlock(&joydev->mutex);
  }
  
  /*
   * Wake up users waiting for IO so they can disconnect from
   * dead device.
   */
  static void joydev_hangup(struct joydev *joydev)
  {
  	struct joydev_client *client;
  
  	spin_lock(&joydev->client_lock);
  	list_for_each_entry(client, &joydev->client_list, node)
  		kill_fasync(&client->fasync, SIGIO, POLL_HUP);
  	spin_unlock(&joydev->client_lock);
  
  	wake_up_interruptible(&joydev->wait);
  }
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
228
  static int joydev_release(struct inode *inode, struct file *file)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
  {
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
230
231
  	struct joydev_client *client = file->private_data;
  	struct joydev *joydev = client->joydev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232

b126207cc   Dmitry Torokhov   Input: joydev - i...
233
  	joydev_detach_client(joydev, client);
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
234
  	kfree(client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235

b126207cc   Dmitry Torokhov   Input: joydev - i...
236
  	joydev_close_device(joydev);
9657d75c5   Dmitry Torokhov   Input: convert fr...
237
  	put_device(&joydev->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
240
241
242
243
  	return 0;
  }
  
  static int joydev_open(struct inode *inode, struct file *file)
  {
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
244
245
  	struct joydev_client *client;
  	struct joydev *joydev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
  	int i = iminor(inode) - JOYDEV_MINOR_BASE;
d542ed82f   Dmitry Torokhov   Input: handlers -...
247
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248

d0ffb9be8   Dmitry Torokhov   Input: handlers -...
249
250
  	if (i >= JOYDEV_MINORS)
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251

b126207cc   Dmitry Torokhov   Input: joydev - i...
252
253
254
  	error = mutex_lock_interruptible(&joydev_table_mutex);
  	if (error)
  		return error;
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
255
  	joydev = joydev_table[i];
b126207cc   Dmitry Torokhov   Input: joydev - i...
256
257
258
  	if (joydev)
  		get_device(&joydev->dev);
  	mutex_unlock(&joydev_table_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259

b126207cc   Dmitry Torokhov   Input: joydev - i...
260
261
  	if (!joydev)
  		return -ENODEV;
9657d75c5   Dmitry Torokhov   Input: convert fr...
262

d0ffb9be8   Dmitry Torokhov   Input: handlers -...
263
  	client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL);
9657d75c5   Dmitry Torokhov   Input: convert fr...
264
265
266
267
  	if (!client) {
  		error = -ENOMEM;
  		goto err_put_joydev;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268

b126207cc   Dmitry Torokhov   Input: joydev - i...
269
  	spin_lock_init(&client->buffer_lock);
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
270
  	client->joydev = joydev;
b126207cc   Dmitry Torokhov   Input: joydev - i...
271
  	joydev_attach_client(joydev, client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272

b126207cc   Dmitry Torokhov   Input: joydev - i...
273
274
275
  	error = joydev_open_device(joydev);
  	if (error)
  		goto err_free_client;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276

d0ffb9be8   Dmitry Torokhov   Input: handlers -...
277
  	file->private_data = client;
3d7bbd457   Dmitry Torokhov   Input: mark input...
278
  	nonseekable_open(inode, file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
  	return 0;
9657d75c5   Dmitry Torokhov   Input: convert fr...
280
281
  
   err_free_client:
b126207cc   Dmitry Torokhov   Input: joydev - i...
282
  	joydev_detach_client(joydev, client);
9657d75c5   Dmitry Torokhov   Input: convert fr...
283
284
285
286
  	kfree(client);
   err_put_joydev:
  	put_device(&joydev->dev);
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
  }
b126207cc   Dmitry Torokhov   Input: joydev - i...
288
289
290
  static int joydev_generate_startup_event(struct joydev_client *client,
  					 struct input_dev *input,
  					 struct js_event *event)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
  {
b126207cc   Dmitry Torokhov   Input: joydev - i...
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
  	struct joydev *joydev = client->joydev;
  	int have_event;
  
  	spin_lock_irq(&client->buffer_lock);
  
  	have_event = client->startup < joydev->nabs + joydev->nkey;
  
  	if (have_event) {
  
  		event->time = jiffies_to_msecs(jiffies);
  		if (client->startup < joydev->nkey) {
  			event->type = JS_EVENT_BUTTON | JS_EVENT_INIT;
  			event->number = client->startup;
  			event->value = !!test_bit(joydev->keypam[event->number],
  						  input->key);
  		} else {
  			event->type = JS_EVENT_AXIS | JS_EVENT_INIT;
  			event->number = client->startup - joydev->nkey;
  			event->value = joydev->abs[event->number];
  		}
  		client->startup++;
  	}
  
  	spin_unlock_irq(&client->buffer_lock);
  
  	return have_event;
  }
  
  static int joydev_fetch_next_event(struct joydev_client *client,
  				   struct js_event *event)
  {
  	int have_event;
  
  	spin_lock_irq(&client->buffer_lock);
  
  	have_event = client->head != client->tail;
  	if (have_event) {
  		*event = client->buffer[client->tail++];
  		client->tail &= JOYDEV_BUFFER_SIZE - 1;
  	}
  
  	spin_unlock_irq(&client->buffer_lock);
  
  	return have_event;
  }
  
  /*
   * Old joystick interface
   */
  static ssize_t joydev_0x_read(struct joydev_client *client,
  			      struct input_dev *input,
  			      char __user *buf)
  {
  	struct joydev *joydev = client->joydev;
  	struct JS_DATA_TYPE data;
  	int i;
  
  	spin_lock_irq(&input->event_lock);
  
  	/*
  	 * Get device state
  	 */
  	for (data.buttons = i = 0; i < 32 && i < joydev->nkey; i++)
  		data.buttons |=
  			test_bit(joydev->keypam[i], input->key) ? (1 << i) : 0;
  	data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x;
  	data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y;
  
  	/*
  	 * Reset reader's event queue
  	 */
  	spin_lock(&client->buffer_lock);
  	client->startup = 0;
  	client->tail = client->head;
  	spin_unlock(&client->buffer_lock);
  
  	spin_unlock_irq(&input->event_lock);
  
  	if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)))
  		return -EFAULT;
  
  	return sizeof(struct JS_DATA_TYPE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
  }
b126207cc   Dmitry Torokhov   Input: joydev - i...
375
376
377
378
379
380
381
382
383
384
  static inline int joydev_data_pending(struct joydev_client *client)
  {
  	struct joydev *joydev = client->joydev;
  
  	return client->startup < joydev->nabs + joydev->nkey ||
  		client->head != client->tail;
  }
  
  static ssize_t joydev_read(struct file *file, char __user *buf,
  			   size_t count, loff_t *ppos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
  {
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
386
387
  	struct joydev_client *client = file->private_data;
  	struct joydev *joydev = client->joydev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
  	struct input_dev *input = joydev->handle.dev;
b126207cc   Dmitry Torokhov   Input: joydev - i...
389
390
  	struct js_event event;
  	int retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391

d0ffb9be8   Dmitry Torokhov   Input: handlers -...
392
  	if (!joydev->exist)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
394
395
396
  		return -ENODEV;
  
  	if (count < sizeof(struct js_event))
  		return -EINVAL;
b126207cc   Dmitry Torokhov   Input: joydev - i...
397
398
  	if (count == sizeof(struct JS_DATA_TYPE))
  		return joydev_0x_read(client, input, buf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
399

b126207cc   Dmitry Torokhov   Input: joydev - i...
400
  	if (!joydev_data_pending(client) && (file->f_flags & O_NONBLOCK))
1e0afb288   Dmitry Torokhov   Input: fix format...
401
  		return -EAGAIN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402

d0ffb9be8   Dmitry Torokhov   Input: handlers -...
403
  	retval = wait_event_interruptible(joydev->wait,
b126207cc   Dmitry Torokhov   Input: joydev - i...
404
  			!joydev->exist || joydev_data_pending(client));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
406
  	if (retval)
  		return retval;
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
407
  	if (!joydev->exist)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
  		return -ENODEV;
b126207cc   Dmitry Torokhov   Input: joydev - i...
409
410
  	while (retval + sizeof(struct js_event) <= count &&
  	       joydev_generate_startup_event(client, input, &event)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
412
413
  
  		if (copy_to_user(buf + retval, &event, sizeof(struct js_event)))
  			return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414
415
  		retval += sizeof(struct js_event);
  	}
b126207cc   Dmitry Torokhov   Input: joydev - i...
416
417
  	while (retval + sizeof(struct js_event) <= count &&
  	       joydev_fetch_next_event(client, &event)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418

b126207cc   Dmitry Torokhov   Input: joydev - i...
419
  		if (copy_to_user(buf + retval, &event, sizeof(struct js_event)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
  			return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421
422
423
424
425
426
427
428
429
  		retval += sizeof(struct js_event);
  	}
  
  	return retval;
  }
  
  /* No kernel lock - fine */
  static unsigned int joydev_poll(struct file *file, poll_table *wait)
  {
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
430
431
  	struct joydev_client *client = file->private_data;
  	struct joydev *joydev = client->joydev;
1e0afb288   Dmitry Torokhov   Input: fix format...
432

d0ffb9be8   Dmitry Torokhov   Input: handlers -...
433
  	poll_wait(file, &joydev->wait, wait);
b126207cc   Dmitry Torokhov   Input: joydev - i...
434
435
  	return (joydev_data_pending(client) ? (POLLIN | POLLRDNORM) : 0) |
  		(joydev->exist ?  0 : (POLLHUP | POLLERR));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
436
  }
999b874f4   Stephen Kitt   Input: joydev - v...
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
  static int joydev_handle_JSIOCSAXMAP(struct joydev *joydev,
  				     void __user *argp, size_t len)
  {
  	__u8 *abspam;
  	int i;
  	int retval = 0;
  
  	len = min(len, sizeof(joydev->abspam));
  
  	/* Validate the map. */
  	abspam = kmalloc(len, GFP_KERNEL);
  	if (!abspam)
  		return -ENOMEM;
  
  	if (copy_from_user(abspam, argp, len)) {
  		retval = -EFAULT;
  		goto out;
  	}
  
  	for (i = 0; i < joydev->nabs; i++) {
  		if (abspam[i] > ABS_MAX) {
  			retval = -EINVAL;
  			goto out;
  		}
  	}
  
  	memcpy(joydev->abspam, abspam, len);
d2520a426   Kenneth Waters   Input: joydev - f...
464
465
  	for (i = 0; i < joydev->nabs; i++)
  		joydev->absmap[joydev->abspam[i]] = i;
999b874f4   Stephen Kitt   Input: joydev - v...
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
   out:
  	kfree(abspam);
  	return retval;
  }
  
  static int joydev_handle_JSIOCSBTNMAP(struct joydev *joydev,
  				      void __user *argp, size_t len)
  {
  	__u16 *keypam;
  	int i;
  	int retval = 0;
  
  	len = min(len, sizeof(joydev->keypam));
  
  	/* Validate the map. */
  	keypam = kmalloc(len, GFP_KERNEL);
  	if (!keypam)
  		return -ENOMEM;
  
  	if (copy_from_user(keypam, argp, len)) {
  		retval = -EFAULT;
  		goto out;
  	}
  
  	for (i = 0; i < joydev->nkey; i++) {
  		if (keypam[i] > KEY_MAX || keypam[i] < BTN_MISC) {
  			retval = -EINVAL;
  			goto out;
  		}
  	}
  
  	memcpy(joydev->keypam, keypam, len);
  
  	for (i = 0; i < joydev->nkey; i++)
  		joydev->keymap[keypam[i] - BTN_MISC] = i;
  
   out:
  	kfree(keypam);
  	return retval;
  }
b126207cc   Dmitry Torokhov   Input: joydev - i...
506
507
  static int joydev_ioctl_common(struct joydev *joydev,
  				unsigned int cmd, void __user *argp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
  	struct input_dev *dev = joydev->handle.dev;
ec8b4b708   Stephen Kitt   Input: joydev - d...
510
  	size_t len;
987a6c029   Daniel Mack   Input: switch to ...
511
  	int i;
ec8b4b708   Stephen Kitt   Input: joydev - d...
512
  	const char *name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513

ec8b4b708   Stephen Kitt   Input: joydev - d...
514
  	/* Process fixed-sized commands. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515
  	switch (cmd) {
b126207cc   Dmitry Torokhov   Input: joydev - i...
516
517
  	case JS_SET_CAL:
  		return copy_from_user(&joydev->glue.JS_CORR, argp,
024ac44c7   Jeremy Fitzhardinge   Input: This patch...
518
  				sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
1e0afb288   Dmitry Torokhov   Input: fix format...
519

b126207cc   Dmitry Torokhov   Input: joydev - i...
520
521
  	case JS_GET_CAL:
  		return copy_to_user(argp, &joydev->glue.JS_CORR,
024ac44c7   Jeremy Fitzhardinge   Input: This patch...
522
  				sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
1e0afb288   Dmitry Torokhov   Input: fix format...
523

b126207cc   Dmitry Torokhov   Input: joydev - i...
524
525
  	case JS_SET_TIMEOUT:
  		return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
1e0afb288   Dmitry Torokhov   Input: fix format...
526

b126207cc   Dmitry Torokhov   Input: joydev - i...
527
528
  	case JS_GET_TIMEOUT:
  		return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529

b126207cc   Dmitry Torokhov   Input: joydev - i...
530
531
  	case JSIOCGVERSION:
  		return put_user(JS_VERSION, (__u32 __user *) argp);
1e0afb288   Dmitry Torokhov   Input: fix format...
532

b126207cc   Dmitry Torokhov   Input: joydev - i...
533
534
  	case JSIOCGAXES:
  		return put_user(joydev->nabs, (__u8 __user *) argp);
1e0afb288   Dmitry Torokhov   Input: fix format...
535

b126207cc   Dmitry Torokhov   Input: joydev - i...
536
537
  	case JSIOCGBUTTONS:
  		return put_user(joydev->nkey, (__u8 __user *) argp);
1e0afb288   Dmitry Torokhov   Input: fix format...
538

b126207cc   Dmitry Torokhov   Input: joydev - i...
539
540
541
  	case JSIOCSCORR:
  		if (copy_from_user(joydev->corr, argp,
  			      sizeof(joydev->corr[0]) * joydev->nabs))
987a6c029   Daniel Mack   Input: switch to ...
542
  			return -EFAULT;
1e0afb288   Dmitry Torokhov   Input: fix format...
543

b126207cc   Dmitry Torokhov   Input: joydev - i...
544
  		for (i = 0; i < joydev->nabs; i++) {
987a6c029   Daniel Mack   Input: switch to ...
545
546
  			int val = input_abs_get_val(dev, joydev->abspam[i]);
  			joydev->abs[i] = joydev_correct(val, &joydev->corr[i]);
b126207cc   Dmitry Torokhov   Input: joydev - i...
547
548
  		}
  		return 0;
1e0afb288   Dmitry Torokhov   Input: fix format...
549

b126207cc   Dmitry Torokhov   Input: joydev - i...
550
551
552
  	case JSIOCGCORR:
  		return copy_to_user(argp, joydev->corr,
  			sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0;
ec8b4b708   Stephen Kitt   Input: joydev - d...
553
554
555
556
557
558
559
560
561
562
  	}
  
  	/*
  	 * Process variable-sized commands (the axis and button map commands
  	 * are considered variable-sized to decouple them from the values of
  	 * ABS_MAX and KEY_MAX).
  	 */
  	switch (cmd & ~IOCSIZE_MASK) {
  
  	case (JSIOCSAXMAP & ~IOCSIZE_MASK):
999b874f4   Stephen Kitt   Input: joydev - v...
563
  		return joydev_handle_JSIOCSAXMAP(joydev, argp, _IOC_SIZE(cmd));
b126207cc   Dmitry Torokhov   Input: joydev - i...
564

ec8b4b708   Stephen Kitt   Input: joydev - d...
565
566
  	case (JSIOCGAXMAP & ~IOCSIZE_MASK):
  		len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->abspam));
999b874f4   Stephen Kitt   Input: joydev - v...
567
  		return copy_to_user(argp, joydev->abspam, len) ? -EFAULT : len;
ec8b4b708   Stephen Kitt   Input: joydev - d...
568
569
  
  	case (JSIOCSBTNMAP & ~IOCSIZE_MASK):
999b874f4   Stephen Kitt   Input: joydev - v...
570
  		return joydev_handle_JSIOCSBTNMAP(joydev, argp, _IOC_SIZE(cmd));
b126207cc   Dmitry Torokhov   Input: joydev - i...
571

ec8b4b708   Stephen Kitt   Input: joydev - d...
572
573
  	case (JSIOCGBTNMAP & ~IOCSIZE_MASK):
  		len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->keypam));
999b874f4   Stephen Kitt   Input: joydev - v...
574
  		return copy_to_user(argp, joydev->keypam, len) ? -EFAULT : len;
b126207cc   Dmitry Torokhov   Input: joydev - i...
575

ec8b4b708   Stephen Kitt   Input: joydev - d...
576
577
578
579
580
581
582
  	case JSIOCGNAME(0):
  		name = dev->name;
  		if (!name)
  			return 0;
  
  		len = min_t(size_t, _IOC_SIZE(cmd), strlen(name) + 1);
  		return copy_to_user(argp, name, len) ? -EFAULT : len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
583
  	}
ec8b4b708   Stephen Kitt   Input: joydev - d...
584

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
586
  	return -EINVAL;
  }
024ac44c7   Jeremy Fitzhardinge   Input: This patch...
587
  #ifdef CONFIG_COMPAT
b126207cc   Dmitry Torokhov   Input: joydev - i...
588
589
  static long joydev_compat_ioctl(struct file *file,
  				unsigned int cmd, unsigned long arg)
024ac44c7   Jeremy Fitzhardinge   Input: This patch...
590
  {
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
591
592
  	struct joydev_client *client = file->private_data;
  	struct joydev *joydev = client->joydev;
024ac44c7   Jeremy Fitzhardinge   Input: This patch...
593
594
595
  	void __user *argp = (void __user *)arg;
  	s32 tmp32;
  	struct JS_DATA_SAVE_TYPE_32 ds32;
b126207cc   Dmitry Torokhov   Input: joydev - i...
596
  	int retval;
024ac44c7   Jeremy Fitzhardinge   Input: This patch...
597

b126207cc   Dmitry Torokhov   Input: joydev - i...
598
599
600
601
602
603
604
605
606
607
  	retval = mutex_lock_interruptible(&joydev->mutex);
  	if (retval)
  		return retval;
  
  	if (!joydev->exist) {
  		retval = -ENODEV;
  		goto out;
  	}
  
  	switch (cmd) {
1e0afb288   Dmitry Torokhov   Input: fix format...
608

024ac44c7   Jeremy Fitzhardinge   Input: This patch...
609
  	case JS_SET_TIMELIMIT:
b126207cc   Dmitry Torokhov   Input: joydev - i...
610
611
  		retval = get_user(tmp32, (s32 __user *) arg);
  		if (retval == 0)
024ac44c7   Jeremy Fitzhardinge   Input: This patch...
612
613
  			joydev->glue.JS_TIMELIMIT = tmp32;
  		break;
b126207cc   Dmitry Torokhov   Input: joydev - i...
614

024ac44c7   Jeremy Fitzhardinge   Input: This patch...
615
616
  	case JS_GET_TIMELIMIT:
  		tmp32 = joydev->glue.JS_TIMELIMIT;
b126207cc   Dmitry Torokhov   Input: joydev - i...
617
  		retval = put_user(tmp32, (s32 __user *) arg);
024ac44c7   Jeremy Fitzhardinge   Input: This patch...
618
619
620
  		break;
  
  	case JS_SET_ALL:
b126207cc   Dmitry Torokhov   Input: joydev - i...
621
622
623
  		retval = copy_from_user(&ds32, argp,
  					sizeof(ds32)) ? -EFAULT : 0;
  		if (retval == 0) {
024ac44c7   Jeremy Fitzhardinge   Input: This patch...
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
  			joydev->glue.JS_TIMEOUT    = ds32.JS_TIMEOUT;
  			joydev->glue.BUSY          = ds32.BUSY;
  			joydev->glue.JS_EXPIRETIME = ds32.JS_EXPIRETIME;
  			joydev->glue.JS_TIMELIMIT  = ds32.JS_TIMELIMIT;
  			joydev->glue.JS_SAVE       = ds32.JS_SAVE;
  			joydev->glue.JS_CORR       = ds32.JS_CORR;
  		}
  		break;
  
  	case JS_GET_ALL:
  		ds32.JS_TIMEOUT    = joydev->glue.JS_TIMEOUT;
  		ds32.BUSY          = joydev->glue.BUSY;
  		ds32.JS_EXPIRETIME = joydev->glue.JS_EXPIRETIME;
  		ds32.JS_TIMELIMIT  = joydev->glue.JS_TIMELIMIT;
  		ds32.JS_SAVE       = joydev->glue.JS_SAVE;
  		ds32.JS_CORR       = joydev->glue.JS_CORR;
b126207cc   Dmitry Torokhov   Input: joydev - i...
640
  		retval = copy_to_user(argp, &ds32, sizeof(ds32)) ? -EFAULT : 0;
024ac44c7   Jeremy Fitzhardinge   Input: This patch...
641
642
643
  		break;
  
  	default:
b126207cc   Dmitry Torokhov   Input: joydev - i...
644
645
  		retval = joydev_ioctl_common(joydev, cmd, argp);
  		break;
024ac44c7   Jeremy Fitzhardinge   Input: This patch...
646
  	}
b126207cc   Dmitry Torokhov   Input: joydev - i...
647
648
649
650
  
   out:
  	mutex_unlock(&joydev->mutex);
  	return retval;
024ac44c7   Jeremy Fitzhardinge   Input: This patch...
651
652
  }
  #endif /* CONFIG_COMPAT */
b126207cc   Dmitry Torokhov   Input: joydev - i...
653
654
  static long joydev_ioctl(struct file *file,
  			 unsigned int cmd, unsigned long arg)
024ac44c7   Jeremy Fitzhardinge   Input: This patch...
655
  {
d0ffb9be8   Dmitry Torokhov   Input: handlers -...
656
657
  	struct joydev_client *client = file->private_data;
  	struct joydev *joydev = client->joydev;
024ac44c7   Jeremy Fitzhardinge   Input: This patch...
658
  	void __user *argp = (void __user *)arg;
b126207cc   Dmitry Torokhov   Input: joydev - i...
659
  	int retval;
024ac44c7   Jeremy Fitzhardinge   Input: This patch...
660

b126207cc   Dmitry Torokhov   Input: joydev - i...
661
662
663
  	retval = mutex_lock_interruptible(&joydev->mutex);
  	if (retval)
  		return retval;
024ac44c7   Jeremy Fitzhardinge   Input: This patch...
664

b126207cc   Dmitry Torokhov   Input: joydev - i...
665
666
667
  	if (!joydev->exist) {
  		retval = -ENODEV;
  		goto out;
024ac44c7   Jeremy Fitzhardinge   Input: This patch...
668
  	}
b126207cc   Dmitry Torokhov   Input: joydev - i...
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
  
  	switch (cmd) {
  
  	case JS_SET_TIMELIMIT:
  		retval = get_user(joydev->glue.JS_TIMELIMIT,
  				  (long __user *) arg);
  		break;
  
  	case JS_GET_TIMELIMIT:
  		retval = put_user(joydev->glue.JS_TIMELIMIT,
  				  (long __user *) arg);
  		break;
  
  	case JS_SET_ALL:
  		retval = copy_from_user(&joydev->glue, argp,
  					sizeof(joydev->glue)) ? -EFAULT: 0;
  		break;
  
  	case JS_GET_ALL:
  		retval = copy_to_user(argp, &joydev->glue,
  				      sizeof(joydev->glue)) ? -EFAULT : 0;
  		break;
  
  	default:
  		retval = joydev_ioctl_common(joydev, cmd, argp);
  		break;
  	}
   out:
  	mutex_unlock(&joydev->mutex);
  	return retval;
024ac44c7   Jeremy Fitzhardinge   Input: This patch...
699
  }
66e661188   Dmitry Torokhov   Input: constify i...
700
  static const struct file_operations joydev_fops = {
b126207cc   Dmitry Torokhov   Input: joydev - i...
701
702
703
704
705
706
  	.owner		= THIS_MODULE,
  	.read		= joydev_read,
  	.poll		= joydev_poll,
  	.open		= joydev_open,
  	.release	= joydev_release,
  	.unlocked_ioctl	= joydev_ioctl,
024ac44c7   Jeremy Fitzhardinge   Input: This patch...
707
  #ifdef CONFIG_COMPAT
b126207cc   Dmitry Torokhov   Input: joydev - i...
708
  	.compat_ioctl	= joydev_compat_ioctl,
024ac44c7   Jeremy Fitzhardinge   Input: This patch...
709
  #endif
b126207cc   Dmitry Torokhov   Input: joydev - i...
710
  	.fasync		= joydev_fasync,
6038f373a   Arnd Bergmann   llseek: automatic...
711
  	.llseek		= no_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
712
  };
b126207cc   Dmitry Torokhov   Input: joydev - i...
713
714
715
716
717
718
719
720
721
722
723
724
725
726
  static int joydev_install_chrdev(struct joydev *joydev)
  {
  	joydev_table[joydev->minor] = joydev;
  	return 0;
  }
  
  static void joydev_remove_chrdev(struct joydev *joydev)
  {
  	mutex_lock(&joydev_table_mutex);
  	joydev_table[joydev->minor] = NULL;
  	mutex_unlock(&joydev_table_mutex);
  }
  
  /*
25985edce   Lucas De Marchi   Fix common misspe...
727
   * Mark device non-existent. This disables writes, ioctls and
b126207cc   Dmitry Torokhov   Input: joydev - i...
728
729
730
731
732
733
   * prevents new users from opening the device. Already posted
   * blocking reads will stay, however new ones will fail.
   */
  static void joydev_mark_dead(struct joydev *joydev)
  {
  	mutex_lock(&joydev->mutex);
20da92de8   Dmitry Torokhov   Input: change inp...
734
  	joydev->exist = false;
b126207cc   Dmitry Torokhov   Input: joydev - i...
735
736
737
738
739
740
741
742
743
744
  	mutex_unlock(&joydev->mutex);
  }
  
  static void joydev_cleanup(struct joydev *joydev)
  {
  	struct input_handle *handle = &joydev->handle;
  
  	joydev_mark_dead(joydev);
  	joydev_hangup(joydev);
  	joydev_remove_chrdev(joydev);
25985edce   Lucas De Marchi   Fix common misspe...
745
  	/* joydev is marked dead so no one else accesses joydev->open */
b126207cc   Dmitry Torokhov   Input: joydev - i...
746
747
748
  	if (joydev->open)
  		input_close_device(handle);
  }
0b7024ac4   Dmitry Torokhov   Input: add match(...
749
750
751
752
753
754
755
756
757
758
759
760
761
  
  static bool joydev_match(struct input_handler *handler, struct input_dev *dev)
  {
  	/* Avoid touchpads and touchscreens */
  	if (test_bit(EV_KEY, dev->evbit) && test_bit(BTN_TOUCH, dev->keybit))
  		return false;
  
  	/* Avoid tablets, digitisers and similar devices */
  	if (test_bit(EV_KEY, dev->evbit) && test_bit(BTN_DIGI, dev->keybit))
  		return false;
  
  	return true;
  }
5b2a08262   Dmitry Torokhov   Input: rework han...
762
763
  static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
  			  const struct input_device_id *id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
764
765
766
  {
  	struct joydev *joydev;
  	int i, j, t, minor;
5b2a08262   Dmitry Torokhov   Input: rework han...
767
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
768

b126207cc   Dmitry Torokhov   Input: joydev - i...
769
770
771
  	for (minor = 0; minor < JOYDEV_MINORS; minor++)
  		if (!joydev_table[minor])
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
772
  	if (minor == JOYDEV_MINORS) {
da0c49011   Joe Perches   Input: use pr_fmt...
773
774
  		pr_err("no more free joydev devices
  ");
5b2a08262   Dmitry Torokhov   Input: rework han...
775
  		return -ENFILE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
776
  	}
5b2a08262   Dmitry Torokhov   Input: rework han...
777
778
779
  	joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL);
  	if (!joydev)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
780

d0ffb9be8   Dmitry Torokhov   Input: handlers -...
781
  	INIT_LIST_HEAD(&joydev->client_list);
b126207cc   Dmitry Torokhov   Input: joydev - i...
782
783
  	spin_lock_init(&joydev->client_lock);
  	mutex_init(&joydev->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
784
  	init_waitqueue_head(&joydev->wait);
3d5cb60ef   Thadeu Lima de Souza Cascardo   Input: simplify n...
785
  	dev_set_name(&joydev->dev, "js%d", minor);
20da92de8   Dmitry Torokhov   Input: change inp...
786
  	joydev->exist = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
787
  	joydev->minor = minor;
b126207cc   Dmitry Torokhov   Input: joydev - i...
788

a7097ff89   Dmitry Torokhov   Input: make sure ...
789
  	joydev->handle.dev = input_get_device(dev);
3d5cb60ef   Thadeu Lima de Souza Cascardo   Input: simplify n...
790
  	joydev->handle.name = dev_name(&joydev->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
791
792
  	joydev->handle.handler = handler;
  	joydev->handle.private = joydev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
793

81c2a3ba4   Daniel Mack   Input: use ABS_CN...
794
  	for (i = 0; i < ABS_CNT; i++)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
795
796
797
798
799
800
801
802
803
804
805
806
  		if (test_bit(i, dev->absbit)) {
  			joydev->absmap[i] = joydev->nabs;
  			joydev->abspam[joydev->nabs] = i;
  			joydev->nabs++;
  		}
  
  	for (i = BTN_JOYSTICK - BTN_MISC; i < KEY_MAX - BTN_MISC + 1; i++)
  		if (test_bit(i + BTN_MISC, dev->keybit)) {
  			joydev->keymap[i] = joydev->nkey;
  			joydev->keypam[joydev->nkey] = i + BTN_MISC;
  			joydev->nkey++;
  		}
f24949e8e   Vojtech Pavlik   Input: Fix button...
807
  	for (i = 0; i < BTN_JOYSTICK - BTN_MISC; i++)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
808
809
810
811
812
813
814
815
  		if (test_bit(i + BTN_MISC, dev->keybit)) {
  			joydev->keymap[i] = joydev->nkey;
  			joydev->keypam[joydev->nkey] = i + BTN_MISC;
  			joydev->nkey++;
  		}
  
  	for (i = 0; i < joydev->nabs; i++) {
  		j = joydev->abspam[i];
987a6c029   Daniel Mack   Input: switch to ...
816
  		if (input_abs_get_max(dev, j) == input_abs_get_min(dev, j)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
817
  			joydev->corr[i].type = JS_CORR_NONE;
987a6c029   Daniel Mack   Input: switch to ...
818
  			joydev->abs[i] = input_abs_get_val(dev, j);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
819
820
821
  			continue;
  		}
  		joydev->corr[i].type = JS_CORR_BROKEN;
987a6c029   Daniel Mack   Input: switch to ...
822
823
824
825
826
  		joydev->corr[i].prec = input_abs_get_fuzz(dev, j);
  
  		t = (input_abs_get_max(dev, j) + input_abs_get_min(dev, j)) / 2;
  		joydev->corr[i].coef[0] = t - input_abs_get_flat(dev, j);
  		joydev->corr[i].coef[1] = t + input_abs_get_flat(dev, j);
b126207cc   Dmitry Torokhov   Input: joydev - i...
827

987a6c029   Daniel Mack   Input: switch to ...
828
829
  		t = (input_abs_get_max(dev, j) - input_abs_get_min(dev, j)) / 2
  			- 2 * input_abs_get_flat(dev, j);
b126207cc   Dmitry Torokhov   Input: joydev - i...
830
831
832
  		if (t) {
  			joydev->corr[i].coef[2] = (1 << 29) / t;
  			joydev->corr[i].coef[3] = (1 << 29) / t;
987a6c029   Daniel Mack   Input: switch to ...
833
834
835
  			joydev->abs[i] =
  				joydev_correct(input_abs_get_val(dev, j),
  					       joydev->corr + i);
b126207cc   Dmitry Torokhov   Input: joydev - i...
836
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
837
  	}
b126207cc   Dmitry Torokhov   Input: joydev - i...
838
  	joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor);
9657d75c5   Dmitry Torokhov   Input: convert fr...
839
840
  	joydev->dev.class = &input_class;
  	joydev->dev.parent = &dev->dev;
9657d75c5   Dmitry Torokhov   Input: convert fr...
841
842
  	joydev->dev.release = joydev_free;
  	device_initialize(&joydev->dev);
5b2a08262   Dmitry Torokhov   Input: rework han...
843

b126207cc   Dmitry Torokhov   Input: joydev - i...
844
  	error = input_register_handle(&joydev->handle);
5b2a08262   Dmitry Torokhov   Input: rework han...
845
  	if (error)
9657d75c5   Dmitry Torokhov   Input: convert fr...
846
  		goto err_free_joydev;
5b2a08262   Dmitry Torokhov   Input: rework han...
847

b126207cc   Dmitry Torokhov   Input: joydev - i...
848
  	error = joydev_install_chrdev(joydev);
5b2a08262   Dmitry Torokhov   Input: rework han...
849
  	if (error)
b126207cc   Dmitry Torokhov   Input: joydev - i...
850
851
852
853
854
  		goto err_unregister_handle;
  
  	error = device_add(&joydev->dev);
  	if (error)
  		goto err_cleanup_joydev;
5b2a08262   Dmitry Torokhov   Input: rework han...
855
856
  
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
857

b126207cc   Dmitry Torokhov   Input: joydev - i...
858
859
860
861
   err_cleanup_joydev:
  	joydev_cleanup(joydev);
   err_unregister_handle:
  	input_unregister_handle(&joydev->handle);
5b2a08262   Dmitry Torokhov   Input: rework han...
862
   err_free_joydev:
9657d75c5   Dmitry Torokhov   Input: convert fr...
863
  	put_device(&joydev->dev);
5b2a08262   Dmitry Torokhov   Input: rework han...
864
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
865
866
867
868
869
  }
  
  static void joydev_disconnect(struct input_handle *handle)
  {
  	struct joydev *joydev = handle->private;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
870

9657d75c5   Dmitry Torokhov   Input: convert fr...
871
  	device_del(&joydev->dev);
b126207cc   Dmitry Torokhov   Input: joydev - i...
872
873
  	joydev_cleanup(joydev);
  	input_unregister_handle(handle);
9657d75c5   Dmitry Torokhov   Input: convert fr...
874
  	put_device(&joydev->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
875
  }
66e661188   Dmitry Torokhov   Input: constify i...
876
  static const struct input_device_id joydev_ids[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
877
  	{
b126207cc   Dmitry Torokhov   Input: joydev - i...
878
879
  		.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
  				INPUT_DEVICE_ID_MATCH_ABSBIT,
7b19ada2e   Jiri Slaby   get rid of input ...
880
881
  		.evbit = { BIT_MASK(EV_ABS) },
  		.absbit = { BIT_MASK(ABS_X) },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
882
883
  	},
  	{
b126207cc   Dmitry Torokhov   Input: joydev - i...
884
885
  		.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
  				INPUT_DEVICE_ID_MATCH_ABSBIT,
7b19ada2e   Jiri Slaby   get rid of input ...
886
887
  		.evbit = { BIT_MASK(EV_ABS) },
  		.absbit = { BIT_MASK(ABS_WHEEL) },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
888
889
  	},
  	{
b126207cc   Dmitry Torokhov   Input: joydev - i...
890
891
  		.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
  				INPUT_DEVICE_ID_MATCH_ABSBIT,
7b19ada2e   Jiri Slaby   get rid of input ...
892
893
  		.evbit = { BIT_MASK(EV_ABS) },
  		.absbit = { BIT_MASK(ABS_THROTTLE) },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
894
  	},
26a6931ba   Christoph Fritz   Input: joydev - a...
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
  	{
  		.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
  				INPUT_DEVICE_ID_MATCH_KEYBIT,
  		.evbit = { BIT_MASK(EV_KEY) },
  		.keybit = {[BIT_WORD(BTN_JOYSTICK)] = BIT_MASK(BTN_JOYSTICK) },
  	},
  	{
  		.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
  				INPUT_DEVICE_ID_MATCH_KEYBIT,
  		.evbit = { BIT_MASK(EV_KEY) },
  		.keybit = { [BIT_WORD(BTN_GAMEPAD)] = BIT_MASK(BTN_GAMEPAD) },
  	},
  	{
  		.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
  				INPUT_DEVICE_ID_MATCH_KEYBIT,
  		.evbit = { BIT_MASK(EV_KEY) },
  		.keybit = { [BIT_WORD(BTN_TRIGGER_HAPPY)] = BIT_MASK(BTN_TRIGGER_HAPPY) },
  	},
1e0afb288   Dmitry Torokhov   Input: fix format...
913
  	{ }	/* Terminating entry */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
914
915
916
917
918
  };
  
  MODULE_DEVICE_TABLE(input, joydev_ids);
  
  static struct input_handler joydev_handler = {
b126207cc   Dmitry Torokhov   Input: joydev - i...
919
  	.event		= joydev_event,
0b7024ac4   Dmitry Torokhov   Input: add match(...
920
  	.match		= joydev_match,
b126207cc   Dmitry Torokhov   Input: joydev - i...
921
922
923
924
925
926
  	.connect	= joydev_connect,
  	.disconnect	= joydev_disconnect,
  	.fops		= &joydev_fops,
  	.minor		= JOYDEV_MINOR_BASE,
  	.name		= "joydev",
  	.id_table	= joydev_ids,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
927
928
929
930
  };
  
  static int __init joydev_init(void)
  {
4263cf0fa   Dmitry Torokhov   Input: make input...
931
  	return input_register_handler(&joydev_handler);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
932
933
934
935
936
937
938
939
940
  }
  
  static void __exit joydev_exit(void)
  {
  	input_unregister_handler(&joydev_handler);
  }
  
  module_init(joydev_init);
  module_exit(joydev_exit);