mousedev.c 25.8 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5 6 7 8 9 10 11
/*
 * Input driver to ExplorerPS/2 device driver module.
 *
 * Copyright (c) 1999-2002 Vojtech Pavlik
 * Copyright (c) 2004      Dmitry Torokhov
 *
 * 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.
 */

Joe Perches's avatar
Joe Perches committed
12 13
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

14
#define MOUSEDEV_MINOR_BASE	32
15 16
#define MOUSEDEV_MINORS		31
#define MOUSEDEV_MIX		63
Linus Torvalds's avatar
Linus Torvalds committed
17

18
#include <linux/bitops.h>
19
#include <linux/sched.h>
Linus Torvalds's avatar
Linus Torvalds committed
20 21 22 23 24 25 26 27
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/random.h>
#include <linux/major.h>
#include <linux/device.h>
28
#include <linux/cdev.h>
29
#include <linux/kernel.h>
Linus Torvalds's avatar
Linus Torvalds committed
30 31 32 33 34 35 36 37 38 39 40 41 42

MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Mouse (ExplorerPS/2) device interfaces");
MODULE_LICENSE("GPL");

#ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_X
#define CONFIG_INPUT_MOUSEDEV_SCREEN_X	1024
#endif
#ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_Y
#define CONFIG_INPUT_MOUSEDEV_SCREEN_Y	768
#endif

static int xres = CONFIG_INPUT_MOUSEDEV_SCREEN_X;
43
module_param(xres, uint, 0644);
Linus Torvalds's avatar
Linus Torvalds committed
44 45 46
MODULE_PARM_DESC(xres, "Horizontal screen resolution");

static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y;
47
module_param(yres, uint, 0644);
Linus Torvalds's avatar
Linus Torvalds committed
48 49 50
MODULE_PARM_DESC(yres, "Vertical screen resolution");

static unsigned tap_time = 200;
51
module_param(tap_time, uint, 0644);
Linus Torvalds's avatar
Linus Torvalds committed
52 53 54 55 56 57 58 59 60 61 62
MODULE_PARM_DESC(tap_time, "Tap time for touchpads in absolute mode (msecs)");

struct mousedev_hw_data {
	int dx, dy, dz;
	int x, y;
	int abs_event;
	unsigned long buttons;
};

struct mousedev {
	int open;
63
	struct input_handle handle;
Linus Torvalds's avatar
Linus Torvalds committed
64
	wait_queue_head_t wait;
65
	struct list_head client_list;
66 67
	spinlock_t client_lock; /* protects client_list */
	struct mutex mutex;
68
	struct device dev;
69
	struct cdev cdev;
70
	bool exist;
Linus Torvalds's avatar
Linus Torvalds committed
71

72
	struct list_head mixdev_node;
73
	bool opened_by_mixdev;
74

Linus Torvalds's avatar
Linus Torvalds committed
75 76 77 78 79
	struct mousedev_hw_data packet;
	unsigned int pkt_count;
	int old_x[4], old_y[4];
	int frac_dx, frac_dy;
	unsigned long touch;
80 81 82

	int (*open_device)(struct mousedev *mousedev);
	void (*close_device)(struct mousedev *mousedev);
Linus Torvalds's avatar
Linus Torvalds committed
83 84 85 86 87 88 89 90 91 92 93 94 95 96
};

enum mousedev_emul {
	MOUSEDEV_EMUL_PS2,
	MOUSEDEV_EMUL_IMPS,
	MOUSEDEV_EMUL_EXPS
};

struct mousedev_motion {
	int dx, dy, dz;
	unsigned long buttons;
};

#define PACKET_QUEUE_LEN	16
97
struct mousedev_client {
Linus Torvalds's avatar
Linus Torvalds committed
98 99 100 101 102 103 104 105 106
	struct fasync_struct *fasync;
	struct mousedev *mousedev;
	struct list_head node;

	struct mousedev_motion packets[PACKET_QUEUE_LEN];
	unsigned int head, tail;
	spinlock_t packet_lock;
	int pos_x, pos_y;

107
	u8 ps2[6];
Linus Torvalds's avatar
Linus Torvalds committed
108 109 110
	unsigned char ready, buffer, bufsiz;
	unsigned char imexseq, impsseq;
	enum mousedev_emul mode;
111
	unsigned long last_buttons;
Linus Torvalds's avatar
Linus Torvalds committed
112 113 114 115 116 117 118
};

#define MOUSEDEV_SEQ_LEN	6

static unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 };
static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 };

119
static struct mousedev *mousedev_mix;
120
static LIST_HEAD(mousedev_mix_list);
Linus Torvalds's avatar
Linus Torvalds committed
121 122 123 124

#define fx(i)  (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
#define fy(i)  (mousedev->old_y[(mousedev->pkt_count - (i)) & 03])

125 126 127
static void mousedev_touchpad_event(struct input_dev *dev,
				    struct mousedev *mousedev,
				    unsigned int code, int value)
Linus Torvalds's avatar
Linus Torvalds committed
128 129 130 131
{
	int size, tmp;
	enum { FRACTION_DENOM = 128 };

132
	switch (code) {
Linus Torvalds's avatar
Linus Torvalds committed
133

134
	case ABS_X:
135

136 137
		fx(0) = value;
		if (mousedev->touch && mousedev->pkt_count >= 2) {
138 139
			size = input_abs_get_max(dev, ABS_X) -
					input_abs_get_min(dev, ABS_X);
140 141
			if (size == 0)
				size = 256 * 2;
142

143 144 145 146 147 148 149 150 151 152 153
			tmp = ((value - fx(2)) * 256 * FRACTION_DENOM) / size;
			tmp += mousedev->frac_dx;
			mousedev->packet.dx = tmp / FRACTION_DENOM;
			mousedev->frac_dx =
				tmp - mousedev->packet.dx * FRACTION_DENOM;
		}
		break;

	case ABS_Y:
		fy(0) = value;
		if (mousedev->touch && mousedev->pkt_count >= 2) {
154
			/* use X size for ABS_Y to keep the same scale */
155 156
			size = input_abs_get_max(dev, ABS_X) -
					input_abs_get_min(dev, ABS_X);
157 158
			if (size == 0)
				size = 256 * 2;
159

160 161 162 163 164 165 166
			tmp = -((value - fy(2)) * 256 * FRACTION_DENOM) / size;
			tmp += mousedev->frac_dy;
			mousedev->packet.dy = tmp / FRACTION_DENOM;
			mousedev->frac_dy = tmp -
				mousedev->packet.dy * FRACTION_DENOM;
		}
		break;
Linus Torvalds's avatar
Linus Torvalds committed
167 168 169
	}
}

170 171
static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev,
				unsigned int code, int value)
Linus Torvalds's avatar
Linus Torvalds committed
172
{
173
	int min, max, size;
Linus Torvalds's avatar
Linus Torvalds committed
174 175 176

	switch (code) {

177
	case ABS_X:
178 179 180 181
		min = input_abs_get_min(dev, ABS_X);
		max = input_abs_get_max(dev, ABS_X);

		size = max - min;
182 183
		if (size == 0)
			size = xres ? : 1;
184

185
		value = clamp(value, min, max);
186 187

		mousedev->packet.x = ((value - min) * xres) / size;
188 189 190 191
		mousedev->packet.abs_event = 1;
		break;

	case ABS_Y:
192 193 194 195
		min = input_abs_get_min(dev, ABS_Y);
		max = input_abs_get_max(dev, ABS_Y);

		size = max - min;
196 197
		if (size == 0)
			size = yres ? : 1;
198

199
		value = clamp(value, min, max);
200 201

		mousedev->packet.y = yres - ((value - min) * yres) / size;
202 203
		mousedev->packet.abs_event = 1;
		break;
Linus Torvalds's avatar
Linus Torvalds committed
204 205 206
	}
}

207 208
static void mousedev_rel_event(struct mousedev *mousedev,
				unsigned int code, int value)
Linus Torvalds's avatar
Linus Torvalds committed
209 210
{
	switch (code) {
211 212 213 214 215 216 217 218 219 220 221
	case REL_X:
		mousedev->packet.dx += value;
		break;

	case REL_Y:
		mousedev->packet.dy -= value;
		break;

	case REL_WHEEL:
		mousedev->packet.dz -= value;
		break;
Linus Torvalds's avatar
Linus Torvalds committed
222 223 224
	}
}

225 226
static void mousedev_key_event(struct mousedev *mousedev,
				unsigned int code, int value)
Linus Torvalds's avatar
Linus Torvalds committed
227 228 229 230
{
	int index;

	switch (code) {
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252

	case BTN_TOUCH:
	case BTN_0:
	case BTN_LEFT:		index = 0; break;

	case BTN_STYLUS:
	case BTN_1:
	case BTN_RIGHT:		index = 1; break;

	case BTN_2:
	case BTN_FORWARD:
	case BTN_STYLUS2:
	case BTN_MIDDLE:	index = 2; break;

	case BTN_3:
	case BTN_BACK:
	case BTN_SIDE:		index = 3; break;

	case BTN_4:
	case BTN_EXTRA:		index = 4; break;

	default:		return;
Linus Torvalds's avatar
Linus Torvalds committed
253 254 255 256
	}

	if (value) {
		set_bit(index, &mousedev->packet.buttons);
257
		set_bit(index, &mousedev_mix->packet.buttons);
Linus Torvalds's avatar
Linus Torvalds committed
258 259
	} else {
		clear_bit(index, &mousedev->packet.buttons);
260
		clear_bit(index, &mousedev_mix->packet.buttons);
Linus Torvalds's avatar
Linus Torvalds committed
261 262 263
	}
}

264 265
static void mousedev_notify_readers(struct mousedev *mousedev,
				    struct mousedev_hw_data *packet)
Linus Torvalds's avatar
Linus Torvalds committed
266
{
267
	struct mousedev_client *client;
Linus Torvalds's avatar
Linus Torvalds committed
268
	struct mousedev_motion *p;
269
	unsigned int new_head;
270
	int wake_readers = 0;
Linus Torvalds's avatar
Linus Torvalds committed
271

Dmitry Torokhov's avatar
Dmitry Torokhov committed
272
	rcu_read_lock();
273 274 275 276
	list_for_each_entry_rcu(client, &mousedev->client_list, node) {

		/* Just acquire the lock, interrupts already disabled */
		spin_lock(&client->packet_lock);
Linus Torvalds's avatar
Linus Torvalds committed
277

278 279
		p = &client->packets[client->head];
		if (client->ready && p->buttons != mousedev->packet.buttons) {
280
			new_head = (client->head + 1) % PACKET_QUEUE_LEN;
281 282
			if (new_head != client->tail) {
				p = &client->packets[client->head = new_head];
Linus Torvalds's avatar
Linus Torvalds committed
283 284 285 286 287
				memset(p, 0, sizeof(struct mousedev_motion));
			}
		}

		if (packet->abs_event) {
288 289 290 291
			p->dx += packet->x - client->pos_x;
			p->dy += packet->y - client->pos_y;
			client->pos_x = packet->x;
			client->pos_y = packet->y;
Linus Torvalds's avatar
Linus Torvalds committed
292 293
		}

294
		client->pos_x += packet->dx;
295 296
		client->pos_x = clamp_val(client->pos_x, 0, xres);

297
		client->pos_y += packet->dy;
298
		client->pos_y = clamp_val(client->pos_y, 0, yres);
Linus Torvalds's avatar
Linus Torvalds committed
299 300 301 302 303 304

		p->dx += packet->dx;
		p->dy += packet->dy;
		p->dz += packet->dz;
		p->buttons = mousedev->packet.buttons;

305 306
		if (p->dx || p->dy || p->dz ||
		    p->buttons != client->last_buttons)
307
			client->ready = 1;
Linus Torvalds's avatar
Linus Torvalds committed
308

309
		spin_unlock(&client->packet_lock);
310

311 312
		if (client->ready) {
			kill_fasync(&client->fasync, SIGIO, POLL_IN);
313 314
			wake_readers = 1;
		}
Linus Torvalds's avatar
Linus Torvalds committed
315
	}
Dmitry Torokhov's avatar
Dmitry Torokhov committed
316
	rcu_read_unlock();
Linus Torvalds's avatar
Linus Torvalds committed
317

318 319
	if (wake_readers)
		wake_up_interruptible(&mousedev->wait);
Linus Torvalds's avatar
Linus Torvalds committed
320 321 322 323 324 325
}

static void mousedev_touchpad_touch(struct mousedev *mousedev, int value)
{
	if (!value) {
		if (mousedev->touch &&
326 327
		    time_before(jiffies,
				mousedev->touch + msecs_to_jiffies(tap_time))) {
Linus Torvalds's avatar
Linus Torvalds committed
328 329 330 331 332 333
			/*
			 * Toggle left button to emulate tap.
			 * We rely on the fact that mousedev_mix always has 0
			 * motion packet so we won't mess current position.
			 */
			set_bit(0, &mousedev->packet.buttons);
334 335
			set_bit(0, &mousedev_mix->packet.buttons);
			mousedev_notify_readers(mousedev, &mousedev_mix->packet);
336 337
			mousedev_notify_readers(mousedev_mix,
						&mousedev_mix->packet);
Linus Torvalds's avatar
Linus Torvalds committed
338
			clear_bit(0, &mousedev->packet.buttons);
339
			clear_bit(0, &mousedev_mix->packet.buttons);
Linus Torvalds's avatar
Linus Torvalds committed
340 341 342 343
		}
		mousedev->touch = mousedev->pkt_count = 0;
		mousedev->frac_dx = 0;
		mousedev->frac_dy = 0;
344 345 346

	} else if (!mousedev->touch)
		mousedev->touch = jiffies;
Linus Torvalds's avatar
Linus Torvalds committed
347 348
}

349 350
static void mousedev_event(struct input_handle *handle,
			   unsigned int type, unsigned int code, int value)
Linus Torvalds's avatar
Linus Torvalds committed
351 352 353 354 355
{
	struct mousedev *mousedev = handle->private;

	switch (type) {

356 357 358 359
	case EV_ABS:
		/* Ignore joysticks */
		if (test_bit(BTN_TRIGGER, handle->dev->keybit))
			return;
Linus Torvalds's avatar
Linus Torvalds committed
360

361 362 363 364 365
		if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
			mousedev_touchpad_event(handle->dev,
						mousedev, code, value);
		else
			mousedev_abs_event(handle->dev, mousedev, code, value);
Linus Torvalds's avatar
Linus Torvalds committed
366

367
		break;
Linus Torvalds's avatar
Linus Torvalds committed
368

369 370 371
	case EV_REL:
		mousedev_rel_event(mousedev, code, value);
		break;
Linus Torvalds's avatar
Linus Torvalds committed
372

373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
	case EV_KEY:
		if (value != 2) {
			if (code == BTN_TOUCH &&
			    test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
				mousedev_touchpad_touch(mousedev, value);
			else
				mousedev_key_event(mousedev, code, value);
		}
		break;

	case EV_SYN:
		if (code == SYN_REPORT) {
			if (mousedev->touch) {
				mousedev->pkt_count++;
				/*
				 * Input system eats duplicate events,
				 * but we need all of them to do correct
				 * averaging so apply present one forward
				 */
				fx(0) = fx(1);
				fy(0) = fy(1);
Linus Torvalds's avatar
Linus Torvalds committed
394
			}
395 396 397 398 399 400 401 402 403

			mousedev_notify_readers(mousedev, &mousedev->packet);
			mousedev_notify_readers(mousedev_mix, &mousedev->packet);

			mousedev->packet.dx = mousedev->packet.dy =
				mousedev->packet.dz = 0;
			mousedev->packet.abs_event = 0;
		}
		break;
Linus Torvalds's avatar
Linus Torvalds committed
404 405 406 407 408
	}
}

static int mousedev_fasync(int fd, struct file *file, int on)
{
409
	struct mousedev_client *client = file->private_data;
410

411
	return fasync_helper(fd, file, on, &client->fasync);
Linus Torvalds's avatar
Linus Torvalds committed
412 413
}

414
static void mousedev_free(struct device *dev)
Linus Torvalds's avatar
Linus Torvalds committed
415
{
416 417
	struct mousedev *mousedev = container_of(dev, struct mousedev, dev);

418
	input_put_device(mousedev->handle.dev);
Linus Torvalds's avatar
Linus Torvalds committed
419 420 421
	kfree(mousedev);
}

422
static int mousedev_open_device(struct mousedev *mousedev)
Linus Torvalds's avatar
Linus Torvalds committed
423
{
424
	int retval;
Linus Torvalds's avatar
Linus Torvalds committed
425

426 427 428
	retval = mutex_lock_interruptible(&mousedev->mutex);
	if (retval)
		return retval;
429

430
	if (!mousedev->exist)
431
		retval = -ENODEV;
432
	else if (!mousedev->open++) {
433
		retval = input_open_device(&mousedev->handle);
434 435 436
		if (retval)
			mousedev->open--;
	}
437

438 439
	mutex_unlock(&mousedev->mutex);
	return retval;
440 441
}

442
static void mousedev_close_device(struct mousedev *mousedev)
443
{
444
	mutex_lock(&mousedev->mutex);
445

446
	if (mousedev->exist && !--mousedev->open)
447 448 449
		input_close_device(&mousedev->handle);

	mutex_unlock(&mousedev->mutex);
450 451
}

452 453 454 455 456
/*
 * Open all available devices so they can all be multiplexed in one.
 * stream. Note that this function is called with mousedev_mix->mutex
 * held.
 */
457
static int mixdev_open_devices(struct mousedev *mixdev)
458
{
459 460 461 462 463
	int error;

	error = mutex_lock_interruptible(&mixdev->mutex);
	if (error)
		return error;
464

465 466
	if (!mixdev->open++) {
		struct mousedev *mousedev;
467

468 469 470 471
		list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
			if (!mousedev->opened_by_mixdev) {
				if (mousedev_open_device(mousedev))
					continue;
472

473 474
				mousedev->opened_by_mixdev = true;
			}
Linus Torvalds's avatar
Linus Torvalds committed
475 476
		}
	}
477 478 479

	mutex_unlock(&mixdev->mutex);
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
480 481
}

482 483 484 485 486
/*
 * Close all devices that were opened as part of multiplexed
 * device. Note that this function is called with mousedev_mix->mutex
 * held.
 */
487
static void mixdev_close_devices(struct mousedev *mixdev)
Linus Torvalds's avatar
Linus Torvalds committed
488
{
489
	mutex_lock(&mixdev->mutex);
490

491 492
	if (!--mixdev->open) {
		struct mousedev *mousedev;
493

494 495 496 497 498
		list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
			if (mousedev->opened_by_mixdev) {
				mousedev->opened_by_mixdev = false;
				mousedev_close_device(mousedev);
			}
Linus Torvalds's avatar
Linus Torvalds committed
499 500
		}
	}
501 502

	mutex_unlock(&mixdev->mutex);
Linus Torvalds's avatar
Linus Torvalds committed
503 504
}

505 506 507 508 509 510 511 512 513 514 515 516 517 518 519

static void mousedev_attach_client(struct mousedev *mousedev,
				   struct mousedev_client *client)
{
	spin_lock(&mousedev->client_lock);
	list_add_tail_rcu(&client->node, &mousedev->client_list);
	spin_unlock(&mousedev->client_lock);
}

static void mousedev_detach_client(struct mousedev *mousedev,
				   struct mousedev_client *client)
{
	spin_lock(&mousedev->client_lock);
	list_del_rcu(&client->node);
	spin_unlock(&mousedev->client_lock);
Dmitry Torokhov's avatar
Dmitry Torokhov committed
520
	synchronize_rcu();
521 522
}

523
static int mousedev_release(struct inode *inode, struct file *file)
Linus Torvalds's avatar
Linus Torvalds committed
524
{
525 526
	struct mousedev_client *client = file->private_data;
	struct mousedev *mousedev = client->mousedev;
Linus Torvalds's avatar
Linus Torvalds committed
527

528
	mousedev_detach_client(mousedev, client);
529
	kfree(client);
Linus Torvalds's avatar
Linus Torvalds committed
530

531
	mousedev->close_device(mousedev);
Linus Torvalds's avatar
Linus Torvalds committed
532 533 534 535

	return 0;
}

536
static int mousedev_open(struct inode *inode, struct file *file)
Linus Torvalds's avatar
Linus Torvalds committed
537
{
538
	struct mousedev_client *client;
Linus Torvalds's avatar
Linus Torvalds committed
539
	struct mousedev *mousedev;
540
	int error;
Linus Torvalds's avatar
Linus Torvalds committed
541 542 543

#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
	if (imajor(inode) == MISC_MAJOR)
544
		mousedev = mousedev_mix;
Linus Torvalds's avatar
Linus Torvalds committed
545 546
	else
#endif
547
		mousedev = container_of(inode->i_cdev, struct mousedev, cdev);
Linus Torvalds's avatar
Linus Torvalds committed
548

549
	client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL);
550 551
	if (!client)
		return -ENOMEM;
Linus Torvalds's avatar
Linus Torvalds committed
552

553 554 555 556
	spin_lock_init(&client->packet_lock);
	client->pos_x = xres / 2;
	client->pos_y = yres / 2;
	client->mousedev = mousedev;
557
	mousedev_attach_client(mousedev, client);
Linus Torvalds's avatar
Linus Torvalds committed
558

559
	error = mousedev->open_device(mousedev);
560 561
	if (error)
		goto err_free_client;
Linus Torvalds's avatar
Linus Torvalds committed
562

563
	file->private_data = client;
564
	nonseekable_open(inode, file);
565

Linus Torvalds's avatar
Linus Torvalds committed
566
	return 0;
567 568

 err_free_client:
569
	mousedev_detach_client(mousedev, client);
570 571
	kfree(client);
	return error;
Linus Torvalds's avatar
Linus Torvalds committed
572 573
}

574
static void mousedev_packet(struct mousedev_client *client, u8 *ps2_data)
Linus Torvalds's avatar
Linus Torvalds committed
575
{
576
	struct mousedev_motion *p = &client->packets[client->tail];
577 578 579 580 581 582 583
	s8 dx, dy, dz;

	dx = clamp_val(p->dx, -127, 127);
	p->dx -= dx;

	dy = clamp_val(p->dy, -127, 127);
	p->dy -= dy;
Linus Torvalds's avatar
Linus Torvalds committed
584

585 586 587 588 589
	ps2_data[0] = BIT(3);
	ps2_data[0] |= ((dx & BIT(7)) >> 3) | ((dy & BIT(7)) >> 2);
	ps2_data[0] |= p->buttons & 0x07;
	ps2_data[1] = dx;
	ps2_data[2] = dy;
Linus Torvalds's avatar
Linus Torvalds committed
590

591
	switch (client->mode) {
592
	case MOUSEDEV_EMUL_EXPS:
593 594 595 596
		dz = clamp_val(p->dz, -7, 7);
		p->dz -= dz;

		ps2_data[3] = (dz & 0x0f) | ((p->buttons & 0x18) << 1);
597 598 599 600
		client->bufsiz = 4;
		break;

	case MOUSEDEV_EMUL_IMPS:
601 602 603 604 605 606 607
		dz = clamp_val(p->dz, -127, 127);
		p->dz -= dz;

		ps2_data[0] |= ((p->buttons & 0x10) >> 3) |
			       ((p->buttons & 0x08) >> 1);
		ps2_data[3] = dz;

608 609 610 611 612 613
		client->bufsiz = 4;
		break;

	case MOUSEDEV_EMUL_PS2:
	default:
		p->dz = 0;
614 615 616 617

		ps2_data[0] |= ((p->buttons & 0x10) >> 3) |
			       ((p->buttons & 0x08) >> 1);

618 619
		client->bufsiz = 3;
		break;
Linus Torvalds's avatar
Linus Torvalds committed
620 621 622
	}

	if (!p->dx && !p->dy && !p->dz) {
623 624 625
		if (client->tail == client->head) {
			client->ready = 0;
			client->last_buttons = p->buttons;
626
		} else
627
			client->tail = (client->tail + 1) % PACKET_QUEUE_LEN;
Linus Torvalds's avatar
Linus Torvalds committed
628 629 630
	}
}

631 632 633 634
static void mousedev_generate_response(struct mousedev_client *client,
					int command)
{
	client->ps2[0] = 0xfa; /* ACK */
Linus Torvalds's avatar
Linus Torvalds committed
635

636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678
	switch (command) {

	case 0xeb: /* Poll */
		mousedev_packet(client, &client->ps2[1]);
		client->bufsiz++; /* account for leading ACK */
		break;

	case 0xf2: /* Get ID */
		switch (client->mode) {
		case MOUSEDEV_EMUL_PS2:
			client->ps2[1] = 0;
			break;
		case MOUSEDEV_EMUL_IMPS:
			client->ps2[1] = 3;
			break;
		case MOUSEDEV_EMUL_EXPS:
			client->ps2[1] = 4;
			break;
		}
		client->bufsiz = 2;
		break;

	case 0xe9: /* Get info */
		client->ps2[1] = 0x60; client->ps2[2] = 3; client->ps2[3] = 200;
		client->bufsiz = 4;
		break;

	case 0xff: /* Reset */
		client->impsseq = client->imexseq = 0;
		client->mode = MOUSEDEV_EMUL_PS2;
		client->ps2[1] = 0xaa; client->ps2[2] = 0x00;
		client->bufsiz = 3;
		break;

	default:
		client->bufsiz = 1;
		break;
	}
	client->buffer = client->bufsiz;
}

static ssize_t mousedev_write(struct file *file, const char __user *buffer,
				size_t count, loff_t *ppos)
Linus Torvalds's avatar
Linus Torvalds committed
679
{
680
	struct mousedev_client *client = file->private_data;
Linus Torvalds's avatar
Linus Torvalds committed
681 682 683 684 685 686 687 688
	unsigned char c;
	unsigned int i;

	for (i = 0; i < count; i++) {

		if (get_user(c, buffer + i))
			return -EFAULT;

689 690
		spin_lock_irq(&client->packet_lock);

691 692 693 694
		if (c == mousedev_imex_seq[client->imexseq]) {
			if (++client->imexseq == MOUSEDEV_SEQ_LEN) {
				client->imexseq = 0;
				client->mode = MOUSEDEV_EMUL_EXPS;
Linus Torvalds's avatar
Linus Torvalds committed
695
			}
696
		} else
697
			client->imexseq = 0;
Linus Torvalds's avatar
Linus Torvalds committed
698

699 700 701 702
		if (c == mousedev_imps_seq[client->impsseq]) {
			if (++client->impsseq == MOUSEDEV_SEQ_LEN) {
				client->impsseq = 0;
				client->mode = MOUSEDEV_EMUL_IMPS;
Linus Torvalds's avatar
Linus Torvalds committed
703
			}
704
		} else
705
			client->impsseq = 0;
Linus Torvalds's avatar
Linus Torvalds committed
706

707
		mousedev_generate_response(client, c);
Linus Torvalds's avatar
Linus Torvalds committed
708

709
		spin_unlock_irq(&client->packet_lock);
Linus Torvalds's avatar
Linus Torvalds committed
710 711
	}

712 713
	kill_fasync(&client->fasync, SIGIO, POLL_IN);
	wake_up_interruptible(&client->mousedev->wait);
Linus Torvalds's avatar
Linus Torvalds committed
714 715 716 717

	return count;
}

718 719
static ssize_t mousedev_read(struct file *file, char __user *buffer,
			     size_t count, loff_t *ppos)
Linus Torvalds's avatar
Linus Torvalds committed
720
{
721
	struct mousedev_client *client = file->private_data;
722
	struct mousedev *mousedev = client->mousedev;
723
	u8 data[sizeof(client->ps2)];
Linus Torvalds's avatar
Linus Torvalds committed
724 725
	int retval = 0;

726 727
	if (!client->ready && !client->buffer && mousedev->exist &&
	    (file->f_flags & O_NONBLOCK))
Linus Torvalds's avatar
Linus Torvalds committed
728 729
		return -EAGAIN;

730 731
	retval = wait_event_interruptible(mousedev->wait,
			!mousedev->exist || client->ready || client->buffer);
Linus Torvalds's avatar
Linus Torvalds committed
732 733 734
	if (retval)
		return retval;

735
	if (!mousedev->exist)
Linus Torvalds's avatar
Linus Torvalds committed
736 737
		return -ENODEV;

738 739
	spin_lock_irq(&client->packet_lock);

740 741 742
	if (!client->buffer && client->ready) {
		mousedev_packet(client, client->ps2);
		client->buffer = client->bufsiz;
Linus Torvalds's avatar
Linus Torvalds committed
743 744
	}

745 746
	if (count > client->buffer)
		count = client->buffer;
Linus Torvalds's avatar
Linus Torvalds committed
747

748
	memcpy(data, client->ps2 + client->bufsiz - client->buffer, count);
749
	client->buffer -= count;
Linus Torvalds's avatar
Linus Torvalds committed
750

751 752 753
	spin_unlock_irq(&client->packet_lock);

	if (copy_to_user(buffer, data, count))
Linus Torvalds's avatar
Linus Torvalds committed
754 755 756 757 758 759 760 761
		return -EFAULT;

	return count;
}

/* No kernel lock - fine */
static unsigned int mousedev_poll(struct file *file, poll_table *wait)
{
762 763
	struct mousedev_client *client = file->private_data;
	struct mousedev *mousedev = client->mousedev;
764
	unsigned int mask;
765

766
	poll_wait(file, &mousedev->wait, wait);
767 768 769 770 771 772

	mask = mousedev->exist ? POLLOUT | POLLWRNORM : POLLHUP | POLLERR;
	if (client->ready || client->buffer)
		mask |= POLLIN | POLLRDNORM;

	return mask;
Linus Torvalds's avatar
Linus Torvalds committed
773 774
}

Dmitry Torokhov's avatar
Dmitry Torokhov committed
775
static const struct file_operations mousedev_fops = {
776 777 778 779 780 781 782 783
	.owner		= THIS_MODULE,
	.read		= mousedev_read,
	.write		= mousedev_write,
	.poll		= mousedev_poll,
	.open		= mousedev_open,
	.release	= mousedev_release,
	.fasync		= mousedev_fasync,
	.llseek		= noop_llseek,
Linus Torvalds's avatar
Linus Torvalds committed
784 785
};

786 787 788 789 790 791 792 793
/*
 * Mark device non-existent. This disables writes, ioctls and
 * prevents new users from opening the device. Already posted
 * blocking reads will stay, however new ones will fail.
 */
static void mousedev_mark_dead(struct mousedev *mousedev)
{
	mutex_lock(&mousedev->mutex);
794
	mousedev->exist = false;
795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819
	mutex_unlock(&mousedev->mutex);
}

/*
 * Wake up users waiting for IO so they can disconnect from
 * dead device.
 */
static void mousedev_hangup(struct mousedev *mousedev)
{
	struct mousedev_client *client;

	spin_lock(&mousedev->client_lock);
	list_for_each_entry(client, &mousedev->client_list, node)
		kill_fasync(&client->fasync, SIGIO, POLL_HUP);
	spin_unlock(&mousedev->client_lock);

	wake_up_interruptible(&mousedev->wait);
}

static void mousedev_cleanup(struct mousedev *mousedev)
{
	struct input_handle *handle = &mousedev->handle;

	mousedev_mark_dead(mousedev);
	mousedev_hangup(mousedev);
820

821 822 823 824 825
	/* mousedev is marked dead so no one else accesses mousedev->open */
	if (mousedev->open)
		input_close_device(handle);
}

826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843
static int mousedev_reserve_minor(bool mixdev)
{
	int minor;

	if (mixdev) {
		minor = input_get_new_minor(MOUSEDEV_MIX, 1, false);
		if (minor < 0)
			pr_err("failed to reserve mixdev minor: %d\n", minor);
	} else {
		minor = input_get_new_minor(MOUSEDEV_MINOR_BASE,
					    MOUSEDEV_MINORS, true);
		if (minor < 0)
			pr_err("failed to reserve new minor: %d\n", minor);
	}

	return minor;
}

844 845
static struct mousedev *mousedev_create(struct input_dev *dev,
					struct input_handler *handler,
846
					bool mixdev)
Linus Torvalds's avatar
Linus Torvalds committed
847 848
{
	struct mousedev *mousedev;
849
	int minor;
850
	int error;
Linus Torvalds's avatar
Linus Torvalds committed
851

852 853 854 855 856 857
	minor = mousedev_reserve_minor(mixdev);
	if (minor < 0) {
		error = minor;
		goto err_out;
	}

858
	mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL);
859 860
	if (!mousedev) {
		error = -ENOMEM;
861
		goto err_free_minor;
862
	}
Linus Torvalds's avatar
Linus Torvalds committed
863

864
	INIT_LIST_HEAD(&mousedev->client_list);
865
	INIT_LIST_HEAD(&mousedev->mixdev_node);
866 867 868
	spin_lock_init(&mousedev->client_lock);
	mutex_init(&mousedev->mutex);
	lockdep_set_subclass(&mousedev->mutex,
869
			     mixdev ? SINGLE_DEPTH_NESTING : 0);
Linus Torvalds's avatar
Linus Torvalds committed
870 871
	init_waitqueue_head(&mousedev->wait);

872
	if (mixdev) {
873
		dev_set_name(&mousedev->dev, "mice");
874 875 876

		mousedev->open_device = mixdev_open_devices;
		mousedev->close_device = mixdev_close_devices;
877 878 879 880 881 882
	} else {
		int dev_no = minor;
		/* Normalize device number if it falls into legacy range */
		if (dev_no < MOUSEDEV_MINOR_BASE + MOUSEDEV_MINORS)
			dev_no -= MOUSEDEV_MINOR_BASE;
		dev_set_name(&mousedev->dev, "mouse%d", dev_no);
883 884 885

		mousedev->open_device = mousedev_open_device;
		mousedev->close_device = mousedev_close_device;
886
	}
887

888
	mousedev->exist = true;
889
	mousedev->handle.dev = input_get_device(dev);
890
	mousedev->handle.name = dev_name(&mousedev->dev);
Linus Torvalds's avatar
Linus Torvalds committed
891 892 893
	mousedev->handle.handler = handler;
	mousedev->handle.private = mousedev;

894 895 896
	mousedev->dev.class = &input_class;
	if (dev)
		mousedev->dev.parent = &dev->dev;
897
	mousedev->dev.devt = MKDEV(INPUT_MAJOR, minor);
898 899
	mousedev->dev.release = mousedev_free;
	device_initialize(&mousedev->dev);
Linus Torvalds's avatar
Linus Torvalds committed
900

901
	if (!mixdev) {
902 903 904 905 906
		error = input_register_handle(&mousedev->handle);
		if (error)
			goto err_free_mousedev;
	}

907
	cdev_init(&mousedev->cdev, &mousedev_fops);
908

909
	error = cdev_device_add(&mousedev->cdev, &mousedev->dev);
910
	if (error)
911
		goto err_cleanup_mousedev;
912 913 914

	return mousedev;

915 916
 err_cleanup_mousedev:
	mousedev_cleanup(mousedev);
917
	if (!mixdev)
918
		input_unregister_handle(&mousedev->handle);
919 920
 err_free_mousedev:
	put_device(&mousedev->dev);
921 922
 err_free_minor:
	input_free_minor(minor);
923 924 925 926 927 928
 err_out:
	return ERR_PTR(error);
}

static void mousedev_destroy(struct mousedev *mousedev)
{
929
	cdev_device_del(&mousedev->cdev, &mousedev->dev);
930
	mousedev_cleanup(mousedev);
931
	input_free_minor(MINOR(mousedev->dev.devt));
932
	if (mousedev != mousedev_mix)
933 934 935
		input_unregister_handle(&mousedev->handle);
	put_device(&mousedev->dev);
}
936

937 938 939 940 941 942 943 944 945 946 947 948 949
static int mixdev_add_device(struct mousedev *mousedev)
{
	int retval;

	retval = mutex_lock_interruptible(&mousedev_mix->mutex);
	if (retval)
		return retval;

	if (mousedev_mix->open) {
		retval = mousedev_open_device(mousedev);
		if (retval)
			goto out;

950
		mousedev->opened_by_mixdev = true;
951
	}
952

953 954 955 956 957 958 959 960 961 962 963 964
	get_device(&mousedev->dev);
	list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list);

 out:
	mutex_unlock(&mousedev_mix->mutex);
	return retval;
}

static void mixdev_remove_device(struct mousedev *mousedev)
{
	mutex_lock(&mousedev_mix->mutex);

965 966
	if (mousedev->opened_by_mixdev) {
		mousedev->opened_by_mixdev = false;
967 968 969 970 971 972
		mousedev_close_device(mousedev);
	}

	list_del_init(&mousedev->mixdev_node);
	mutex_unlock(&mousedev_mix->mutex);

973 974 975
	put_device(&mousedev->dev);
}

976 977
static int mousedev_connect(struct input_handler *handler,
			    struct input_dev *dev,
978 979 980 981 982
			    const struct input_device_id *id)
{
	struct mousedev *mousedev;
	int error;

983
	mousedev = mousedev_create(dev, handler, false);
984 985
	if (IS_ERR(mousedev))
		return PTR_ERR(mousedev);
986

987
	error = mixdev_add_device(mousedev);
988 989 990 991
	if (error) {
		mousedev_destroy(mousedev);
		return error;
	}
Linus Torvalds's avatar
Linus Torvalds committed
992

993
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
994 995 996 997 998 999
}

static void mousedev_disconnect(struct input_handle *handle)
{
	struct mousedev *mousedev = handle->private;

1000
	mixdev_remove_device(mousedev);
1001
	mousedev_destroy(mousedev);
Linus Torvalds's avatar
Linus Torvalds committed
1002 1003
}

Dmitry Torokhov's avatar
Dmitry Torokhov committed
1004
static const struct input_device_id mousedev_ids[] = {
Linus Torvalds's avatar
Linus Torvalds committed
1005
	{
1006 1007 1008
		.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
				INPUT_DEVICE_ID_MATCH_KEYBIT |
				INPUT_DEVICE_ID_MATCH_RELBIT,
1009 1010 1011
		.evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_REL) },
		.keybit = { [BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) },
		.relbit = { BIT_MASK(REL_X) | BIT_MASK(REL_Y) },
1012 1013
	},	/* A mouse like device, at least one button,
		   two relative axes */
Linus Torvalds's avatar
Linus Torvalds committed
1014
	{
1015 1016
		.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
				INPUT_DEVICE_ID_MATCH_RELBIT,
1017 1018
		.evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_REL) },
		.relbit = { BIT_MASK(REL_WHEEL) },
Linus Torvalds's avatar
Linus Torvalds committed
1019 1020
	},	/* A separate scrollwheel */
	{
1021 1022 1023
		.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
				INPUT_DEVICE_ID_MATCH_KEYBIT |
				INPUT_DEVICE_ID_MATCH_ABSBIT,
1024 1025 1026
		.evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) },
		.keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) },
		.absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) },
1027 1028
	},	/* A tablet like device, at least touch detection,
		   two absolute axes */
Linus Torvalds's avatar
Linus Torvalds committed
1029
	{
1030 1031 1032
		.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
				INPUT_DEVICE_ID_MATCH_KEYBIT |
				INPUT_DEVICE_ID_MATCH_ABSBIT,
1033 1034 1035 1036 1037 1038
		.evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) },
		.keybit = { [BIT_WORD(BTN_TOOL_FINGER)] =
				BIT_MASK(BTN_TOOL_FINGER) },
		.absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) |
				BIT_MASK(ABS_PRESSURE) |
				BIT_MASK(ABS_TOOL_WIDTH) },
Linus Torvalds's avatar
Linus Torvalds committed
1039
	},	/* A touchpad */
1040 1041 1042 1043
	{
		.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
			INPUT_DEVICE_ID_MATCH_KEYBIT |
			INPUT_DEVICE_ID_MATCH_ABSBIT,
1044
		.evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) },
1045 1046 1047 1048
		.keybit = { [BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) },
		.absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) },
	},	/* Mouse-like device with absolute X and Y but ordinary
		   clicks, like hp ILO2 High Performance mouse */
Linus Torvalds's avatar
Linus Torvalds committed
1049

1050
	{ },	/* Terminating entry */
Linus Torvalds's avatar
Linus Torvalds committed
1051 1052 1053 1054 1055
};

MODULE_DEVICE_TABLE(input, mousedev_ids);

static struct input_handler mousedev_handler = {
1056 1057 1058
	.event		= mousedev_event,
	.connect	= mousedev_connect,
	.disconnect	= mousedev_disconnect,
1059
	.legacy_minors	= true,
1060 1061 1062
	.minor		= MOUSEDEV_MINOR_BASE,
	.name		= "mousedev",
	.id_table	= mousedev_ids,
Linus Torvalds's avatar
Linus Torvalds committed
1063 1064 1065
};

#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
1066 1067
#include <linux/miscdevice.h>

Linus Torvalds's avatar
Linus Torvalds committed
1068
static struct miscdevice psaux_mouse = {
1069