mousedev.c 25.9 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.
 */

12
#define MOUSEDEV_MINOR_BASE	32
Linus Torvalds's avatar
Linus Torvalds committed
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
#define MOUSEDEV_MINORS		32
#define MOUSEDEV_MIX		31

#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>
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
#include <linux/miscdevice.h>
#endif

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;
40
module_param(xres, uint, 0644);
Linus Torvalds's avatar
Linus Torvalds committed
41 42 43
MODULE_PARM_DESC(xres, "Horizontal screen resolution");

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

static unsigned tap_time = 200;
48
module_param(tap_time, uint, 0644);
Linus Torvalds's avatar
Linus Torvalds committed
49 50 51 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 exist;
	int open;
	int minor;
	char name[16];
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;
Linus Torvalds's avatar
Linus Torvalds committed
69

70 71 72
	struct list_head mixdev_node;
	int mixdev_open;

Linus Torvalds's avatar
Linus Torvalds committed
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
	struct mousedev_hw_data packet;
	unsigned int pkt_count;
	int old_x[4], old_y[4];
	int frac_dx, frac_dy;
	unsigned long touch;
};

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
92
struct mousedev_client {
Linus Torvalds's avatar
Linus Torvalds committed
93 94 95 96 97 98 99 100 101 102 103 104 105
	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;

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

#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 };

static struct input_handler mousedev_handler;

static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
117
static DEFINE_MUTEX(mousedev_table_mutex);
118
static struct mousedev *mousedev_mix;
119
static LIST_HEAD(mousedev_mix_list);
Linus Torvalds's avatar
Linus Torvalds committed
120

121 122 123
static void mixdev_open_devices(void);
static void mixdev_close_devices(void);

Linus Torvalds's avatar
Linus Torvalds committed
124 125 126
#define fx(i)  (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
#define fy(i)  (mousedev->old_y[(mousedev->pkt_count - (i)) & 03])

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

134
	switch (code) {
Linus Torvalds's avatar
Linus Torvalds committed
135

136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
	case ABS_X:
		fx(0) = value;
		if (mousedev->touch && mousedev->pkt_count >= 2) {
			size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
			if (size == 0)
				size = 256 * 2;
			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) {
			/* use X size to keep the same scale */
			size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
			if (size == 0)
				size = 256 * 2;
			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
164 165 166
	}
}

167 168
static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev,
				unsigned int code, int value)
Linus Torvalds's avatar
Linus Torvalds committed
169 170 171 172 173
{
	int size;

	switch (code) {

174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
	case ABS_X:
		size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
		if (size == 0)
			size = xres ? : 1;
		if (value > dev->absmax[ABS_X])
			value = dev->absmax[ABS_X];
		if (value < dev->absmin[ABS_X])
			value = dev->absmin[ABS_X];
		mousedev->packet.x =
			((value - dev->absmin[ABS_X]) * xres) / size;
		mousedev->packet.abs_event = 1;
		break;

	case ABS_Y:
		size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y];
		if (size == 0)
			size = yres ? : 1;
		if (value > dev->absmax[ABS_Y])
			value = dev->absmax[ABS_Y];
		if (value < dev->absmin[ABS_Y])
			value = dev->absmin[ABS_Y];
		mousedev->packet.y = yres -
			((value - dev->absmin[ABS_Y]) * yres) / size;
		mousedev->packet.abs_event = 1;
		break;
Linus Torvalds's avatar
Linus Torvalds committed
199 200 201
	}
}

202 203
static void mousedev_rel_event(struct mousedev *mousedev,
				unsigned int code, int value)
Linus Torvalds's avatar
Linus Torvalds committed
204 205
{
	switch (code) {
206 207 208 209 210 211 212 213 214 215 216
	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
217 218 219
	}
}

220 221
static void mousedev_key_event(struct mousedev *mousedev,
				unsigned int code, int value)
Linus Torvalds's avatar
Linus Torvalds committed
222 223 224 225
{
	int index;

	switch (code) {
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247

	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
248 249 250 251
	}

	if (value) {
		set_bit(index, &mousedev->packet.buttons);
252
		set_bit(index, &mousedev_mix->packet.buttons);
Linus Torvalds's avatar
Linus Torvalds committed
253 254
	} else {
		clear_bit(index, &mousedev->packet.buttons);
255
		clear_bit(index, &mousedev_mix->packet.buttons);
Linus Torvalds's avatar
Linus Torvalds committed
256 257 258
	}
}

259 260
static void mousedev_notify_readers(struct mousedev *mousedev,
				    struct mousedev_hw_data *packet)
Linus Torvalds's avatar
Linus Torvalds committed
261
{
262
	struct mousedev_client *client;
Linus Torvalds's avatar
Linus Torvalds committed
263
	struct mousedev_motion *p;
264
	unsigned int new_head;
265
	int wake_readers = 0;
Linus Torvalds's avatar
Linus Torvalds committed
266

Dmitry Torokhov's avatar
Dmitry Torokhov committed
267
	rcu_read_lock();
268 269 270 271
	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
272

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

		if (packet->abs_event) {
283 284 285 286
			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
287 288
		}

289
		client->pos_x += packet->dx;
290 291
		client->pos_x = client->pos_x < 0 ?
			0 : (client->pos_x >= xres ? xres : client->pos_x);
292
		client->pos_y += packet->dy;
293 294
		client->pos_y = client->pos_y < 0 ?
			0 : (client->pos_y >= yres ? yres : client->pos_y);
Linus Torvalds's avatar
Linus Torvalds committed
295 296 297 298 299 300

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

301 302
		if (p->dx || p->dy || p->dz ||
		    p->buttons != client->last_buttons)
303
			client->ready = 1;
Linus Torvalds's avatar
Linus Torvalds committed
304

305
		spin_unlock(&client->packet_lock);
306

307 308
		if (client->ready) {
			kill_fasync(&client->fasync, SIGIO, POLL_IN);
309 310
			wake_readers = 1;
		}
Linus Torvalds's avatar
Linus Torvalds committed
311
	}
Dmitry Torokhov's avatar
Dmitry Torokhov committed
312
	rcu_read_unlock();
Linus Torvalds's avatar
Linus Torvalds committed
313

314 315
	if (wake_readers)
		wake_up_interruptible(&mousedev->wait);
Linus Torvalds's avatar
Linus Torvalds committed
316 317 318 319 320 321
}

static void mousedev_touchpad_touch(struct mousedev *mousedev, int value)
{
	if (!value) {
		if (mousedev->touch &&
322 323
		    time_before(jiffies,
				mousedev->touch + msecs_to_jiffies(tap_time))) {
Linus Torvalds's avatar
Linus Torvalds committed
324 325 326 327 328 329
			/*
			 * 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);
330 331
			set_bit(0, &mousedev_mix->packet.buttons);
			mousedev_notify_readers(mousedev, &mousedev_mix->packet);
332 333
			mousedev_notify_readers(mousedev_mix,
						&mousedev_mix->packet);
Linus Torvalds's avatar
Linus Torvalds committed
334
			clear_bit(0, &mousedev->packet.buttons);
335
			clear_bit(0, &mousedev_mix->packet.buttons);
Linus Torvalds's avatar
Linus Torvalds committed
336 337 338 339
		}
		mousedev->touch = mousedev->pkt_count = 0;
		mousedev->frac_dx = 0;
		mousedev->frac_dy = 0;
340 341 342

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

345 346
static void mousedev_event(struct input_handle *handle,
			   unsigned int type, unsigned int code, int value)
Linus Torvalds's avatar
Linus Torvalds committed
347 348 349 350 351
{
	struct mousedev *mousedev = handle->private;

	switch (type) {

352 353 354 355
	case EV_ABS:
		/* Ignore joysticks */
		if (test_bit(BTN_TRIGGER, handle->dev->keybit))
			return;
Linus Torvalds's avatar
Linus Torvalds committed
356

357 358 359 360 361
		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
362

363
		break;
Linus Torvalds's avatar
Linus Torvalds committed
364

365 366 367
	case EV_REL:
		mousedev_rel_event(mousedev, code, value);
		break;
Linus Torvalds's avatar
Linus Torvalds committed
368

369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389
	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
390
			}
391 392 393 394 395 396 397 398 399

			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
400 401 402 403 404 405
	}
}

static int mousedev_fasync(int fd, struct file *file, int on)
{
	int retval;
406
	struct mousedev_client *client = file->private_data;
407

408
	retval = fasync_helper(fd, file, on, &client->fasync);
409

Linus Torvalds's avatar
Linus Torvalds committed
410 411 412
	return retval < 0 ? retval : 0;
}

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

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

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

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

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

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

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

447 448 449 450 451 452
	if (mousedev->minor == MOUSEDEV_MIX)
		mixdev_close_devices();
	else if (mousedev->exist && !--mousedev->open)
		input_close_device(&mousedev->handle);

	mutex_unlock(&mousedev->mutex);
453 454
}

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

464 465 466
	if (mousedev_mix->open++)
		return;

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

472
			mousedev->mixdev_open = 1;
Linus Torvalds's avatar
Linus Torvalds committed
473 474 475 476
		}
	}
}

477 478 479 480 481
/*
 * Close all devices that were opened as part of multiplexed
 * device. Note that this function is called with mousedev_mix->mutex
 * held.
 */
482
static void mixdev_close_devices(void)
Linus Torvalds's avatar
Linus Torvalds committed
483
{
484
	struct mousedev *mousedev;
485

486 487 488 489
	if (--mousedev_mix->open)
		return;

	list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
490 491
		if (mousedev->mixdev_open) {
			mousedev->mixdev_open = 0;
492
			mousedev_close_device(mousedev);
Linus Torvalds's avatar
Linus Torvalds committed
493 494 495 496
		}
	}
}

497 498 499 500 501 502 503

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);
Dmitry Torokhov's avatar
Dmitry Torokhov committed
504
	synchronize_rcu();
505 506 507 508 509 510 511 512
}

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
513
	synchronize_rcu();
514 515
}

516
static int mousedev_release(struct inode *inode, struct file *file)
Linus Torvalds's avatar
Linus Torvalds committed
517
{
518 519
	struct mousedev_client *client = file->private_data;
	struct mousedev *mousedev = client->mousedev;
Linus Torvalds's avatar
Linus Torvalds committed
520 521

	mousedev_fasync(-1, file, 0);
522
	mousedev_detach_client(mousedev, client);
523
	kfree(client);
Linus Torvalds's avatar
Linus Torvalds committed
524

525
	mousedev_close_device(mousedev);
526
	put_device(&mousedev->dev);
Linus Torvalds's avatar
Linus Torvalds committed
527 528 529 530

	return 0;
}

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

#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
	if (imajor(inode) == MISC_MAJOR)
		i = MOUSEDEV_MIX;
	else
#endif
		i = iminor(inode) - MOUSEDEV_MINOR_BASE;

545
	if (i >= MOUSEDEV_MINORS)
Linus Torvalds's avatar
Linus Torvalds committed
546 547
		return -ENODEV;

548 549 550
	error = mutex_lock_interruptible(&mousedev_table_mutex);
	if (error)
		return error;
551
	mousedev = mousedev_table[i];
552 553 554 555
	if (mousedev)
		get_device(&mousedev->dev);
	mutex_unlock(&mousedev_table_mutex);

556
	if (!mousedev)
Linus Torvalds's avatar
Linus Torvalds committed
557 558
		return -ENODEV;

559
	client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL);
560 561 562 563
	if (!client) {
		error = -ENOMEM;
		goto err_put_mousedev;
	}
Linus Torvalds's avatar
Linus Torvalds committed
564

565 566 567 568
	spin_lock_init(&client->packet_lock);
	client->pos_x = xres / 2;
	client->pos_y = yres / 2;
	client->mousedev = mousedev;
569
	mousedev_attach_client(mousedev, client);
Linus Torvalds's avatar
Linus Torvalds committed
570

571 572 573
	error = mousedev_open_device(mousedev);
	if (error)
		goto err_free_client;
Linus Torvalds's avatar
Linus Torvalds committed
574

575
	file->private_data = client;
Linus Torvalds's avatar
Linus Torvalds committed
576
	return 0;
577 578

 err_free_client:
579
	mousedev_detach_client(mousedev, client);
580 581 582 583
	kfree(client);
 err_put_mousedev:
	put_device(&mousedev->dev);
	return error;
Linus Torvalds's avatar
Linus Torvalds committed
584 585 586 587 588 589 590
}

static inline int mousedev_limit_delta(int delta, int limit)
{
	return delta > limit ? limit : (delta < -limit ? -limit : delta);
}

591 592
static void mousedev_packet(struct mousedev_client *client,
			    signed char *ps2_data)
Linus Torvalds's avatar
Linus Torvalds committed
593
{
594
	struct mousedev_motion *p = &client->packets[client->tail];
Linus Torvalds's avatar
Linus Torvalds committed
595

596 597
	ps2_data[0] = 0x08 |
		((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07);
Linus Torvalds's avatar
Linus Torvalds committed
598 599 600 601 602
	ps2_data[1] = mousedev_limit_delta(p->dx, 127);
	ps2_data[2] = mousedev_limit_delta(p->dy, 127);
	p->dx -= ps2_data[1];
	p->dy -= ps2_data[2];

603
	switch (client->mode) {
604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625
	case MOUSEDEV_EMUL_EXPS:
		ps2_data[3] = mousedev_limit_delta(p->dz, 7);
		p->dz -= ps2_data[3];
		ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1);
		client->bufsiz = 4;
		break;

	case MOUSEDEV_EMUL_IMPS:
		ps2_data[0] |=
			((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
		ps2_data[3] = mousedev_limit_delta(p->dz, 127);
		p->dz -= ps2_data[3];
		client->bufsiz = 4;
		break;

	case MOUSEDEV_EMUL_PS2:
	default:
		ps2_data[0] |=
			((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
		p->dz = 0;
		client->bufsiz = 3;
		break;
Linus Torvalds's avatar
Linus Torvalds committed
626 627 628
	}

	if (!p->dx && !p->dy && !p->dz) {
629 630 631
		if (client->tail == client->head) {
			client->ready = 0;
			client->last_buttons = p->buttons;
632
		} else
633
			client->tail = (client->tail + 1) % PACKET_QUEUE_LEN;
Linus Torvalds's avatar
Linus Torvalds committed
634 635 636
	}
}

637 638 639 640
static void mousedev_generate_response(struct mousedev_client *client,
					int command)
{
	client->ps2[0] = 0xfa; /* ACK */
Linus Torvalds's avatar
Linus Torvalds committed
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 679 680 681 682 683 684
	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
685
{
686
	struct mousedev_client *client = file->private_data;
Linus Torvalds's avatar
Linus Torvalds committed
687 688 689 690 691 692 693 694
	unsigned char c;
	unsigned int i;

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

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

695 696
		spin_lock_irq(&client->packet_lock);

697 698 699 700
		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
701
			}
702
		} else
703
			client->imexseq = 0;
Linus Torvalds's avatar
Linus Torvalds committed
704

705 706 707 708
		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
709
			}
710
		} else
711
			client->impsseq = 0;
Linus Torvalds's avatar
Linus Torvalds committed
712

713
		mousedev_generate_response(client, c);
Linus Torvalds's avatar
Linus Torvalds committed
714

715
		spin_unlock_irq(&client->packet_lock);
Linus Torvalds's avatar
Linus Torvalds committed
716 717
	}

718 719
	kill_fasync(&client->fasync, SIGIO, POLL_IN);
	wake_up_interruptible(&client->mousedev->wait);
Linus Torvalds's avatar
Linus Torvalds committed
720 721 722 723

	return count;
}

724 725
static ssize_t mousedev_read(struct file *file, char __user *buffer,
			     size_t count, loff_t *ppos)
Linus Torvalds's avatar
Linus Torvalds committed
726
{
727
	struct mousedev_client *client = file->private_data;
728 729
	struct mousedev *mousedev = client->mousedev;
	signed char data[sizeof(client->ps2)];
Linus Torvalds's avatar
Linus Torvalds committed
730 731
	int retval = 0;

732 733
	if (!client->ready && !client->buffer && mousedev->exist &&
	    (file->f_flags & O_NONBLOCK))
Linus Torvalds's avatar
Linus Torvalds committed
734 735
		return -EAGAIN;

736 737
	retval = wait_event_interruptible(mousedev->wait,
			!mousedev->exist || client->ready || client->buffer);
Linus Torvalds's avatar
Linus Torvalds committed
738 739 740
	if (retval)
		return retval;

741
	if (!mousedev->exist)
Linus Torvalds's avatar
Linus Torvalds committed
742 743
		return -ENODEV;

744 745
	spin_lock_irq(&client->packet_lock);

746 747 748
	if (!client->buffer && client->ready) {
		mousedev_packet(client, client->ps2);
		client->buffer = client->bufsiz;
Linus Torvalds's avatar
Linus Torvalds committed
749 750
	}

751 752
	if (count > client->buffer)
		count = client->buffer;
Linus Torvalds's avatar
Linus Torvalds committed
753

754
	memcpy(data, client->ps2 + client->bufsiz - client->buffer, count);
755
	client->buffer -= count;
Linus Torvalds's avatar
Linus Torvalds committed
756

757 758 759
	spin_unlock_irq(&client->packet_lock);

	if (copy_to_user(buffer, data, count))
Linus Torvalds's avatar
Linus Torvalds committed
760 761 762 763 764 765 766 767
		return -EFAULT;

	return count;
}

/* No kernel lock - fine */
static unsigned int mousedev_poll(struct file *file, poll_table *wait)
{
768 769
	struct mousedev_client *client = file->private_data;
	struct mousedev *mousedev = client->mousedev;
770

771 772 773
	poll_wait(file, &mousedev->wait, wait);
	return ((client->ready || client->buffer) ? (POLLIN | POLLRDNORM) : 0) |
		(mousedev->exist ? 0 : (POLLHUP | POLLERR));
Linus Torvalds's avatar
Linus Torvalds committed
774 775
}

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

786 787 788 789 790 791 792 793 794 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 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839
static int mousedev_install_chrdev(struct mousedev *mousedev)
{
	mousedev_table[mousedev->minor] = mousedev;
	return 0;
}

static void mousedev_remove_chrdev(struct mousedev *mousedev)
{
	mutex_lock(&mousedev_table_mutex);
	mousedev_table[mousedev->minor] = NULL;
	mutex_unlock(&mousedev_table_mutex);
}

/*
 * 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);
	mousedev->exist = 0;
	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);
	mousedev_remove_chrdev(mousedev);

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

840 841 842
static struct mousedev *mousedev_create(struct input_dev *dev,
					struct input_handler *handler,
					int minor)
Linus Torvalds's avatar
Linus Torvalds committed
843 844
{
	struct mousedev *mousedev;
845
	int error;
Linus Torvalds's avatar
Linus Torvalds committed
846

847
	mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL);
848 849 850 851
	if (!mousedev) {
		error = -ENOMEM;
		goto err_out;
	}
Linus Torvalds's avatar
Linus Torvalds committed
852

853
	INIT_LIST_HEAD(&mousedev->client_list);
854
	INIT_LIST_HEAD(&mousedev->mixdev_node);
855 856 857 858
	spin_lock_init(&mousedev->client_lock);
	mutex_init(&mousedev->mutex);
	lockdep_set_subclass(&mousedev->mutex,
			     minor == MOUSEDEV_MIX ? MOUSEDEV_MIX : 0);
Linus Torvalds's avatar
Linus Torvalds committed
859 860
	init_waitqueue_head(&mousedev->wait);

861 862 863 864 865 866
	if (minor == MOUSEDEV_MIX)
		strlcpy(mousedev->name, "mice", sizeof(mousedev->name));
	else
		snprintf(mousedev->name, sizeof(mousedev->name),
			 "mouse%d", minor);

Linus Torvalds's avatar
Linus Torvalds committed
867 868
	mousedev->minor = minor;
	mousedev->exist = 1;
869
	mousedev->handle.dev = input_get_device(dev);
Linus Torvalds's avatar
Linus Torvalds committed
870 871 872 873
	mousedev->handle.name = mousedev->name;
	mousedev->handle.handler = handler;
	mousedev->handle.private = mousedev;

874 875 876 877 878 879 880 881
	strlcpy(mousedev->dev.bus_id, mousedev->name,
		sizeof(mousedev->dev.bus_id));
	mousedev->dev.class = &input_class;
	if (dev)
		mousedev->dev.parent = &dev->dev;
	mousedev->dev.devt = MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor);
	mousedev->dev.release = mousedev_free;
	device_initialize(&mousedev->dev);
Linus Torvalds's avatar
Linus Torvalds committed
882

883 884 885 886 887 888 889 890 891
	if (minor != MOUSEDEV_MIX) {
		error = input_register_handle(&mousedev->handle);
		if (error)
			goto err_free_mousedev;
	}

	error = mousedev_install_chrdev(mousedev);
	if (error)
		goto err_unregister_handle;
892

893 894
	error = device_add(&mousedev->dev);
	if (error)
895
		goto err_cleanup_mousedev;
896 897 898

	return mousedev;

899 900 901 902 903
 err_cleanup_mousedev:
	mousedev_cleanup(mousedev);
 err_unregister_handle:
	if (minor != MOUSEDEV_MIX)
		input_unregister_handle(&mousedev->handle);
904 905 906 907 908 909 910 911 912
 err_free_mousedev:
	put_device(&mousedev->dev);
 err_out:
	return ERR_PTR(error);
}

static void mousedev_destroy(struct mousedev *mousedev)
{
	device_del(&mousedev->dev);
913 914 915 916 917
	mousedev_cleanup(mousedev);
	if (mousedev->minor != MOUSEDEV_MIX)
		input_unregister_handle(&mousedev->handle);
	put_device(&mousedev->dev);
}
918

919 920 921 922 923 924 925 926 927 928 929 930 931 932
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;

		mousedev->mixdev_open = 1;
933
	}
934

935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954
	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);

	if (mousedev->mixdev_open) {
		mousedev->mixdev_open = 0;
		mousedev_close_device(mousedev);
	}

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

955 956 957
	put_device(&mousedev->dev);
}

958 959
static int mousedev_connect(struct input_handler *handler,
			    struct input_dev *dev,
960 961 962 963 964 965
			    const struct input_device_id *id)
{
	struct mousedev *mousedev;
	int minor;
	int error;

966 967 968 969
	for (minor = 0; minor < MOUSEDEV_MINORS; minor++)
		if (!mousedev_table[minor])
			break;

970 971 972 973 974 975 976 977
	if (minor == MOUSEDEV_MINORS) {
		printk(KERN_ERR "mousedev: no more free mousedev devices\n");
		return -ENFILE;
	}

	mousedev = mousedev_create(dev, handler, minor);
	if (IS_ERR(mousedev))
		return PTR_ERR(mousedev);
978

979
	error = mixdev_add_device(mousedev);
980 981 982 983
	if (error) {
		mousedev_destroy(mousedev);
		return error;
	}
Linus Torvalds's avatar
Linus Torvalds committed
984

985
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
986 987 988 989 990 991
}

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

992
	mixdev_remove_device(mousedev);
993
	mousedev_destroy(mousedev);
Linus Torvalds's avatar
Linus Torvalds committed
994 995
}

Dmitry Torokhov's avatar
Dmitry Torokhov committed
996
static const struct input_device_id mousedev_ids[] = {
Linus Torvalds's avatar
Linus Torvalds committed
997
	{
998 999 1000
		.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
				INPUT_DEVICE_ID_MATCH_KEYBIT |
				INPUT_DEVICE_ID_MATCH_RELBIT,
1001 1002 1003
		.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) },
1004 1005
	},	/* A mouse like device, at least one button,
		   two relative axes */
Linus Torvalds's avatar
Linus Torvalds committed
1006
	{
1007 1008
		.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
				INPUT_DEVICE_ID_MATCH_RELBIT,
1009 1010
		.evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_REL) },
		.relbit = { BIT_MASK(REL_WHEEL) },
Linus Torvalds's avatar
Linus Torvalds committed
1011 1012
	},	/* A separate scrollwheel */
	{
1013 1014 1015
		.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
				INPUT_DEVICE_ID_MATCH_KEYBIT |
				INPUT_DEVICE_ID_MATCH_ABSBIT,
1016 1017 1018
		.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) },
1019 1020
	},	/* A tablet like device, at least touch detection,
		   two absolute axes */
Linus Torvalds's avatar
Linus Torvalds committed
1021
	{
1022 1023 1024
		.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
				INPUT_DEVICE_ID_MATCH_KEYBIT |
				INPUT_DEVICE_ID_MATCH_ABSBIT,
1025 1026 1027 1028 1029 1030
		.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
1031
	},	/* A touchpad */
1032 1033 1034 1035
	{
		.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
			INPUT_DEVICE_ID_MATCH_KEYBIT |
			INPUT_DEVICE_ID_MATCH_ABSBIT,
1036
		.evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) },
1037 1038 1039 1040
		.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
1041

1042
	{ },	/* Terminating entry */
Linus Torvalds's avatar
Linus Torvalds committed
1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065
};

MODULE_DEVICE_TABLE(input, mousedev_ids);

static struct input_handler mousedev_handler = {
	.event =	mousedev_event,
	.connect =	mousedev_connect,
	.disconnect =	mousedev_disconnect,
	.fops =		&mousedev_fops,
	.minor =	MOUSEDEV_MINOR_BASE,
	.name =		"mousedev",
	.id_table =	mousedev_ids,
};

#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
static struct miscdevice psaux_mouse = {
	PSMOUSE_MINOR, "psaux", &mousedev_fops
};
static int psaux_registered;
#endif

static int __init mousedev_init(void)
{
1066 1067
	int error;

1068 1069 1070 1071
	mousedev_mix = mousedev_create(NULL, &mousedev_handler, MOUSEDEV_MIX);
	if (IS_ERR(mousedev_mix))
		return PTR_ERR(mousedev_mix);

1072
	error = input_register_handler(&mousedev_handler);
1073 1074
	if (error) {
		mousedev_destroy(mousedev_mix);
1075 1076
		return error;
	}
Linus Torvalds's avatar
Linus Torvalds committed
1077 1078

#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
1079 1080 1081 1082 1083 1084
	error = misc_register(&psaux_mouse);
	if (error)
		printk(KERN_WARNING "mice: could not register psaux device, "
			"error: %d\n", error);
	else
		psaux_registered = 1;
Linus Torvalds's avatar
Linus Torvalds committed
1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098
#endif

	printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n");

	return 0;
}

static void __exit mousedev_exit(void)
{
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
	if (psaux_registered)
		misc_deregister(&psaux_mouse);
#endif
	input_unregister_handler(&mousedev_handler);
1099
	mousedev_destroy(mousedev_mix);
Linus Torvalds's avatar
Linus Torvalds committed
1100 1101 1102 1103
}

module_init(mousedev_init);
module_exit(mousedev_exit);