/*
* 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.
*/
#define MOUSEDEV_MINOR_BASE 32
#define MOUSEDEV_MINORS 32
#define MOUSEDEV_MIX 31
#include <linux/sched.h>
#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>
#include <linux/kernel.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;
module_param(xres, uint, 0644);
MODULE_PARM_DESC(xres, "Horizontal screen resolution");
static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y;
module_param(yres, uint, 0644);
MODULE_PARM_DESC(yres, "Vertical screen resolution");
static unsigned tap_time = 200;
module_param(tap_time, uint, 0644);
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;
int minor;
struct input_handle handle;
wait_queue_head_t wait;
struct list_head client_list;
spinlock_t client_lock; /* protects client_list */
struct mutex mutex;
struct device dev;
bool exist;
struct list_head mixdev_node;
int mixdev_open;
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
struct mousedev_client {
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;
unsigned long last_buttons;
};
#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];
static DEFINE_MUTEX(mousedev_table_mutex);
static struct mousedev *mousedev_mix;
static LIST_HEAD(mousedev_mix_list);
static void mixdev_open_devices(void);
static void mixdev_close_devices(void);
#define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
#define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03])
static void mousedev_touchpad_event(struct input_dev *dev,
struct mousedev *mousedev,
unsigned int code, int value)
{
int size, tmp;
enum { FRACTION_DENOM = 128 };
switch (code) {
case ABS_X:
fx(0) = value;
if (mousedev->touch && mousedev->pkt_count >= 2) {
size =