joydev.c 16.6 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
/*
 * 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.
 */

#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>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/device.h>

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

struct joydev {
	int exist;
	int open;
	int minor;
	char name[16];
	struct input_handle handle;
	wait_queue_head_t wait;
45
	struct list_head client_list;
46 47
	struct device dev;

L
Linus Torvalds 已提交
48 49 50 51 52 53 54 55 56 57 58
	struct js_corr corr[ABS_MAX + 1];
	struct JS_DATA_SAVE_TYPE glue;
	int nabs;
	int nkey;
	__u16 keymap[KEY_MAX - BTN_MISC + 1];
	__u16 keypam[KEY_MAX - BTN_MISC + 1];
	__u8 absmap[ABS_MAX + 1];
	__u8 abspam[ABS_MAX + 1];
	__s16 abs[ABS_MAX + 1];
};

59
struct joydev_client {
L
Linus Torvalds 已提交
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
	struct js_event buffer[JOYDEV_BUFFER_SIZE];
	int head;
	int tail;
	int startup;
	struct fasync_struct *fasync;
	struct joydev *joydev;
	struct list_head node;
};

static struct joydev *joydev_table[JOYDEV_MINORS];

static int joydev_correct(int value, struct js_corr *corr)
{
	switch (corr->type) {
		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;
	}

85
	return value < -32767 ? -32767 : (value > 32767 ? 32767 : value);
L
Linus Torvalds 已提交
86 87 88 89 90
}

static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
	struct joydev *joydev = handle->private;
91
	struct joydev_client *client;
L
Linus Torvalds 已提交
92 93 94 95 96
	struct js_event event;

	switch (type) {

		case EV_KEY:
97 98
			if (code < BTN_MISC || value == 2)
				return;
L
Linus Torvalds 已提交
99 100 101 102 103 104 105 106 107
			event.type = JS_EVENT_BUTTON;
			event.number = joydev->keymap[code - BTN_MISC];
			event.value = value;
			break;

		case EV_ABS:
			event.type = JS_EVENT_AXIS;
			event.number = joydev->absmap[code];
			event.value = joydev_correct(value, joydev->corr + event.number);
108 109
			if (event.value == joydev->abs[event.number])
				return;
L
Linus Torvalds 已提交
110 111 112 113 114 115 116
			joydev->abs[event.number] = event.value;
			break;

		default:
			return;
	}

117
	event.time = jiffies_to_msecs(jiffies);
L
Linus Torvalds 已提交
118

119
	list_for_each_entry(client, &joydev->client_list, node) {
L
Linus Torvalds 已提交
120

121
		memcpy(client->buffer + client->head, &event, sizeof(struct js_event));
L
Linus Torvalds 已提交
122

123 124 125
		if (client->startup == joydev->nabs + joydev->nkey)
			if (client->tail == (client->head = (client->head + 1) & (JOYDEV_BUFFER_SIZE - 1)))
				client->startup = 0;
L
Linus Torvalds 已提交
126

127
		kill_fasync(&client->fasync, SIGIO, POLL_IN);
L
Linus Torvalds 已提交
128 129 130 131 132 133 134 135
	}

	wake_up_interruptible(&joydev->wait);
}

static int joydev_fasync(int fd, struct file *file, int on)
{
	int retval;
136
	struct joydev_client *client = file->private_data;
137

138
	retval = fasync_helper(fd, file, on, &client->fasync);
139

L
Linus Torvalds 已提交
140 141 142
	return retval < 0 ? retval : 0;
}

143
static void joydev_free(struct device *dev)
L
Linus Torvalds 已提交
144
{
145 146
	struct joydev *joydev = container_of(dev, struct joydev, dev);

L
Linus Torvalds 已提交
147 148 149 150
	joydev_table[joydev->minor] = NULL;
	kfree(joydev);
}

151
static int joydev_release(struct inode *inode, struct file *file)
L
Linus Torvalds 已提交
152
{
153 154
	struct joydev_client *client = file->private_data;
	struct joydev *joydev = client->joydev;
L
Linus Torvalds 已提交
155 156 157

	joydev_fasync(-1, file, 0);

158 159
	list_del(&client->node);
	kfree(client);
L
Linus Torvalds 已提交
160

161 162 163 164
	if (!--joydev->open && joydev->exist)
		input_close_device(&joydev->handle);

	put_device(&joydev->dev);
L
Linus Torvalds 已提交
165 166 167 168 169 170

	return 0;
}

static int joydev_open(struct inode *inode, struct file *file)
{
171 172
	struct joydev_client *client;
	struct joydev *joydev;
L
Linus Torvalds 已提交
173
	int i = iminor(inode) - JOYDEV_MINOR_BASE;
174
	int error;
L
Linus Torvalds 已提交
175

176 177
	if (i >= JOYDEV_MINORS)
		return -ENODEV;
L
Linus Torvalds 已提交
178

179 180
	joydev = joydev_table[i];
	if (!joydev || !joydev->exist)
L
Linus Torvalds 已提交
181 182
		return -ENODEV;

183 184
	get_device(&joydev->dev);

185
	client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL);
186 187 188 189
	if (!client) {
		error = -ENOMEM;
		goto err_put_joydev;
	}
L
Linus Torvalds 已提交
190

191 192
	client->joydev = joydev;
	list_add_tail(&client->node, &joydev->client_list);
L
Linus Torvalds 已提交
193

194 195
	if (!joydev->open++ && joydev->exist) {
		error = input_open_device(&joydev->handle);
196 197
		if (error)
			goto err_free_client;
198
	}
L
Linus Torvalds 已提交
199

200
	file->private_data = client;
L
Linus Torvalds 已提交
201
	return 0;
202 203 204 205 206 207 208

 err_free_client:
	list_del(&client->node);
	kfree(client);
 err_put_joydev:
	put_device(&joydev->dev);
	return error;
L
Linus Torvalds 已提交
209 210
}

211
static ssize_t joydev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
L
Linus Torvalds 已提交
212 213 214 215 216 217
{
	return -EINVAL;
}

static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
218 219
	struct joydev_client *client = file->private_data;
	struct joydev *joydev = client->joydev;
L
Linus Torvalds 已提交
220 221 222
	struct input_dev *input = joydev->handle.dev;
	int retval = 0;

223
	if (!joydev->exist)
L
Linus Torvalds 已提交
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
		return -ENODEV;

	if (count < sizeof(struct js_event))
		return -EINVAL;

	if (count == sizeof(struct JS_DATA_TYPE)) {

		struct JS_DATA_TYPE data;
		int i;

		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;

		if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)))
			return -EFAULT;

242 243
		client->startup = 0;
		client->tail = client->head;
L
Linus Torvalds 已提交
244 245 246 247

		return sizeof(struct JS_DATA_TYPE);
	}

248 249
	if (client->startup == joydev->nabs + joydev->nkey &&
	    client->head == client->tail && (file->f_flags & O_NONBLOCK))
250
		return -EAGAIN;
L
Linus Torvalds 已提交
251

252 253 254 255
	retval = wait_event_interruptible(joydev->wait,
					  !joydev->exist ||
					  client->startup < joydev->nabs + joydev->nkey ||
					  client->head != client->tail);
L
Linus Torvalds 已提交
256 257 258
	if (retval)
		return retval;

259
	if (!joydev->exist)
L
Linus Torvalds 已提交
260 261
		return -ENODEV;

262
	while (client->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) {
L
Linus Torvalds 已提交
263 264 265

		struct js_event event;

266
		event.time = jiffies_to_msecs(jiffies);
L
Linus Torvalds 已提交
267

268
		if (client->startup < joydev->nkey) {
L
Linus Torvalds 已提交
269
			event.type = JS_EVENT_BUTTON | JS_EVENT_INIT;
270
			event.number = client->startup;
L
Linus Torvalds 已提交
271 272 273
			event.value = !!test_bit(joydev->keypam[event.number], input->key);
		} else {
			event.type = JS_EVENT_AXIS | JS_EVENT_INIT;
274
			event.number = client->startup - joydev->nkey;
L
Linus Torvalds 已提交
275 276 277 278 279 280
			event.value = joydev->abs[event.number];
		}

		if (copy_to_user(buf + retval, &event, sizeof(struct js_event)))
			return -EFAULT;

281
		client->startup++;
L
Linus Torvalds 已提交
282 283 284
		retval += sizeof(struct js_event);
	}

285
	while (client->head != client->tail && retval + sizeof(struct js_event) <= count) {
L
Linus Torvalds 已提交
286

287
		if (copy_to_user(buf + retval, client->buffer + client->tail, sizeof(struct js_event)))
L
Linus Torvalds 已提交
288 289
			return -EFAULT;

290
		client->tail = (client->tail + 1) & (JOYDEV_BUFFER_SIZE - 1);
L
Linus Torvalds 已提交
291 292 293 294 295 296 297 298 299
		retval += sizeof(struct js_event);
	}

	return retval;
}

/* No kernel lock - fine */
static unsigned int joydev_poll(struct file *file, poll_table *wait)
{
300 301
	struct joydev_client *client = file->private_data;
	struct joydev *joydev = client->joydev;
302

303 304 305
	poll_wait(file, &joydev->wait, wait);
	return ((client->head != client->tail || client->startup < joydev->nabs + joydev->nkey) ?
		(POLLIN | POLLRDNORM) : 0) | (joydev->exist ? 0 : (POLLHUP | POLLERR));
L
Linus Torvalds 已提交
306 307
}

308
static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __user *argp)
L
Linus Torvalds 已提交
309 310 311 312 313 314 315 316
{
	struct input_dev *dev = joydev->handle.dev;
	int i, j;

	switch (cmd) {

		case JS_SET_CAL:
			return copy_from_user(&joydev->glue.JS_CORR, argp,
317
				sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
318

L
Linus Torvalds 已提交
319 320
		case JS_GET_CAL:
			return copy_to_user(argp, &joydev->glue.JS_CORR,
321
				sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
322

L
Linus Torvalds 已提交
323
		case JS_SET_TIMEOUT:
324
			return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
325

L
Linus Torvalds 已提交
326
		case JS_GET_TIMEOUT:
327
			return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
L
Linus Torvalds 已提交
328 329

		case JSIOCGVERSION:
330
			return put_user(JS_VERSION, (__u32 __user *) argp);
331

L
Linus Torvalds 已提交
332
		case JSIOCGAXES:
333
			return put_user(joydev->nabs, (__u8 __user *) argp);
334

L
Linus Torvalds 已提交
335
		case JSIOCGBUTTONS:
336
			return put_user(joydev->nkey, (__u8 __user *) argp);
337

L
Linus Torvalds 已提交
338 339
		case JSIOCSCORR:
			if (copy_from_user(joydev->corr, argp,
340
				      sizeof(joydev->corr[0]) * joydev->nabs))
L
Linus Torvalds 已提交
341 342 343 344 345 346
			    return -EFAULT;
			for (i = 0; i < joydev->nabs; i++) {
				j = joydev->abspam[i];
			        joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i);
			}
			return 0;
347

L
Linus Torvalds 已提交
348 349
		case JSIOCGCORR:
			return copy_to_user(argp, joydev->corr,
350
						sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0;
351

L
Linus Torvalds 已提交
352 353 354 355
		case JSIOCSAXMAP:
			if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * (ABS_MAX + 1)))
				return -EFAULT;
			for (i = 0; i < joydev->nabs; i++) {
356 357
				if (joydev->abspam[i] > ABS_MAX)
					return -EINVAL;
L
Linus Torvalds 已提交
358 359 360
				joydev->absmap[joydev->abspam[i]] = i;
			}
			return 0;
361

L
Linus Torvalds 已提交
362 363 364
		case JSIOCGAXMAP:
			return copy_to_user(argp, joydev->abspam,
						sizeof(__u8) * (ABS_MAX + 1)) ? -EFAULT : 0;
365

L
Linus Torvalds 已提交
366 367 368 369
		case JSIOCSBTNMAP:
			if (copy_from_user(joydev->keypam, argp, sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)))
				return -EFAULT;
			for (i = 0; i < joydev->nkey; i++) {
370 371
				if (joydev->keypam[i] > KEY_MAX || joydev->keypam[i] < BTN_MISC)
					return -EINVAL;
L
Linus Torvalds 已提交
372 373 374
				joydev->keymap[joydev->keypam[i] - BTN_MISC] = i;
			}
			return 0;
375

L
Linus Torvalds 已提交
376 377 378
		case JSIOCGBTNMAP:
			return copy_to_user(argp, joydev->keypam,
						sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)) ? -EFAULT : 0;
379

L
Linus Torvalds 已提交
380 381 382
		default:
			if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) {
				int len;
383 384
				if (!dev->name)
					return 0;
L
Linus Torvalds 已提交
385
				len = strlen(dev->name) + 1;
386 387 388 389
				if (len > _IOC_SIZE(cmd))
					len = _IOC_SIZE(cmd);
				if (copy_to_user(argp, dev->name, len))
					return -EFAULT;
L
Linus Torvalds 已提交
390 391 392 393 394 395
				return len;
			}
	}
	return -EINVAL;
}

396 397 398
#ifdef CONFIG_COMPAT
static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
399 400
	struct joydev_client *client = file->private_data;
	struct joydev *joydev = client->joydev;
401 402 403 404 405
	void __user *argp = (void __user *)arg;
	s32 tmp32;
	struct JS_DATA_SAVE_TYPE_32 ds32;
	int err;

406 407 408
	if (!joydev->exist)
		return -ENODEV;

409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
	switch(cmd) {
	case JS_SET_TIMELIMIT:
		err = get_user(tmp32, (s32 __user *) arg);
		if (err == 0)
			joydev->glue.JS_TIMELIMIT = tmp32;
		break;
	case JS_GET_TIMELIMIT:
		tmp32 = joydev->glue.JS_TIMELIMIT;
		err = put_user(tmp32, (s32 __user *) arg);
		break;

	case JS_SET_ALL:
		err = copy_from_user(&ds32, argp,
				     sizeof(ds32)) ? -EFAULT : 0;
		if (err == 0) {
			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;

441
		err = copy_to_user(argp, &ds32, sizeof(ds32)) ? -EFAULT : 0;
442 443 444 445 446 447 448 449 450 451 452
		break;

	default:
		err = joydev_ioctl_common(joydev, cmd, argp);
	}
	return err;
}
#endif /* CONFIG_COMPAT */

static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
453 454
	struct joydev_client *client = file->private_data;
	struct joydev *joydev = client->joydev;
455 456
	void __user *argp = (void __user *)arg;

457 458
	if (!joydev->exist)
		return -ENODEV;
459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475

	switch(cmd) {
		case JS_SET_TIMELIMIT:
			return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
		case JS_GET_TIMELIMIT:
			return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
		case JS_SET_ALL:
			return copy_from_user(&joydev->glue, argp,
						sizeof(joydev->glue)) ? -EFAULT : 0;
		case JS_GET_ALL:
			return copy_to_user(argp, &joydev->glue,
						sizeof(joydev->glue)) ? -EFAULT : 0;
		default:
			return joydev_ioctl_common(joydev, cmd, argp);
	}
}

D
Dmitry Torokhov 已提交
476
static const struct file_operations joydev_fops = {
L
Linus Torvalds 已提交
477 478 479 480 481 482 483
	.owner =	THIS_MODULE,
	.read =		joydev_read,
	.write =	joydev_write,
	.poll =		joydev_poll,
	.open =		joydev_open,
	.release =	joydev_release,
	.ioctl =	joydev_ioctl,
484 485 486
#ifdef CONFIG_COMPAT
	.compat_ioctl =	joydev_compat_ioctl,
#endif
L
Linus Torvalds 已提交
487 488 489
	.fasync =	joydev_fasync,
};

490 491
static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
			  const struct input_device_id *id)
L
Linus Torvalds 已提交
492 493 494
{
	struct joydev *joydev;
	int i, j, t, minor;
495
	int error;
L
Linus Torvalds 已提交
496 497 498 499

	for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);
	if (minor == JOYDEV_MINORS) {
		printk(KERN_ERR "joydev: no more free joydev devices\n");
500
		return -ENFILE;
L
Linus Torvalds 已提交
501 502
	}

503 504 505
	joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL);
	if (!joydev)
		return -ENOMEM;
L
Linus Torvalds 已提交
506

507
	INIT_LIST_HEAD(&joydev->client_list);
L
Linus Torvalds 已提交
508 509 510 511 512 513 514 515
	init_waitqueue_head(&joydev->wait);

	joydev->minor = minor;
	joydev->exist = 1;
	joydev->handle.dev = dev;
	joydev->handle.name = joydev->name;
	joydev->handle.handler = handler;
	joydev->handle.private = joydev;
516
	snprintf(joydev->name, sizeof(joydev->name), "js%d", minor);
L
Linus Torvalds 已提交
517 518 519 520 521 522 523 524 525 526 527 528 529 530 531

	for (i = 0; i < ABS_MAX + 1; i++)
		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++;
		}

532
	for (i = 0; i < BTN_JOYSTICK - BTN_MISC; i++)
L
Linus Torvalds 已提交
533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557
		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];
		if (dev->absmax[j] == dev->absmin[j]) {
			joydev->corr[i].type = JS_CORR_NONE;
			joydev->abs[i] = dev->abs[j];
			continue;
		}
		joydev->corr[i].type = JS_CORR_BROKEN;
		joydev->corr[i].prec = dev->absfuzz[j];
		joydev->corr[i].coef[0] = (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j];
		joydev->corr[i].coef[1] = (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j];
		if (!(t = ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j])))
			continue;
		joydev->corr[i].coef[2] = (1 << 29) / t;
		joydev->corr[i].coef[3] = (1 << 29) / t;

		joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i);
	}

558 559 560 561 562 563 564
	snprintf(joydev->dev.bus_id, sizeof(joydev->dev.bus_id),
		 "js%d", minor);
	joydev->dev.class = &input_class;
	joydev->dev.parent = &dev->dev;
	joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor);
	joydev->dev.release = joydev_free;
	device_initialize(&joydev->dev);
565

566
	joydev_table[minor] = joydev;
567

568
	error = device_add(&joydev->dev);
569
	if (error)
570
		goto err_free_joydev;
571 572 573

	error = input_register_handle(&joydev->handle);
	if (error)
574
		goto err_delete_joydev;
575 576

	return 0;
L
Linus Torvalds 已提交
577

578 579
 err_delete_joydev:
	device_del(&joydev->dev);
580
 err_free_joydev:
581
	put_device(&joydev->dev);
582
	return error;
L
Linus Torvalds 已提交
583 584
}

585

L
Linus Torvalds 已提交
586 587 588
static void joydev_disconnect(struct input_handle *handle)
{
	struct joydev *joydev = handle->private;
589
	struct joydev_client *client;
L
Linus Torvalds 已提交
590

591
	input_unregister_handle(handle);
592
	device_del(&joydev->dev);
L
Linus Torvalds 已提交
593 594 595 596 597

	joydev->exist = 0;

	if (joydev->open) {
		input_close_device(handle);
598 599
		list_for_each_entry(client, &joydev->client_list, node)
			kill_fasync(&client->fasync, SIGIO, POLL_HUP);
600
		wake_up_interruptible(&joydev->wait);
601 602 603
	}

	put_device(&joydev->dev);
L
Linus Torvalds 已提交
604 605
}

D
Dmitry Torokhov 已提交
606
static const struct input_device_id joydev_blacklist[] = {
L
Linus Torvalds 已提交
607 608 609 610
	{
		.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
		.evbit = { BIT(EV_KEY) },
		.keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
611 612
	},	/* Avoid itouchpads, touchscreens and tablets */
	{ }	/* Terminating entry */
L
Linus Torvalds 已提交
613 614
};

D
Dmitry Torokhov 已提交
615
static const struct input_device_id joydev_ids[] = {
L
Linus Torvalds 已提交
616 617 618 619 620 621 622 623 624 625 626 627 628 629 630
	{
		.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
		.evbit = { BIT(EV_ABS) },
		.absbit = { BIT(ABS_X) },
	},
	{
		.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
		.evbit = { BIT(EV_ABS) },
		.absbit = { BIT(ABS_WHEEL) },
	},
	{
		.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
		.evbit = { BIT(EV_ABS) },
		.absbit = { BIT(ABS_THROTTLE) },
	},
631
	{ }	/* Terminating entry */
L
Linus Torvalds 已提交
632 633 634 635 636 637 638 639 640 641 642 643
};

MODULE_DEVICE_TABLE(input, joydev_ids);

static struct input_handler joydev_handler = {
	.event =	joydev_event,
	.connect =	joydev_connect,
	.disconnect =	joydev_disconnect,
	.fops =		&joydev_fops,
	.minor =	JOYDEV_MINOR_BASE,
	.name =		"joydev",
	.id_table =	joydev_ids,
644
	.blacklist =	joydev_blacklist,
L
Linus Torvalds 已提交
645 646 647 648
};

static int __init joydev_init(void)
{
649
	return input_register_handler(&joydev_handler);
L
Linus Torvalds 已提交
650 651 652 653 654 655 656 657 658
}

static void __exit joydev_exit(void)
{
	input_unregister_handler(&joydev_handler);
}

module_init(joydev_init);
module_exit(joydev_exit);