Commit 80d06064 authored by Vojtech Pavlik's avatar Vojtech Pavlik

Merge bk://dtor.bkbits.net/input into suse.cz:/home/vojtech/bk/input

parents ccbcf771 9c99b2b0
...@@ -652,6 +652,12 @@ running once the system is up. ...@@ -652,6 +652,12 @@ running once the system is up.
mga= [HW,DRM] mga= [HW,DRM]
mousedev.tap_time=
[MOUSE] Maximum time between finger touching and
leaving touchpad surface for touch to be considered
a tap and be reported as a left button click (for
touchpads working in absolute mode only).
Format: <msecs>
mousedev.xres= [MOUSE] Horizontal screen resolution, used for devices mousedev.xres= [MOUSE] Horizontal screen resolution, used for devices
reporting absolute coordinates, such as tablets reporting absolute coordinates, such as tablets
mousedev.yres= [MOUSE] Vertical screen resolution, used for devices mousedev.yres= [MOUSE] Vertical screen resolution, used for devices
......
...@@ -30,8 +30,6 @@ config MOUSE_PS2 ...@@ -30,8 +30,6 @@ config MOUSE_PS2
and a new verion of GPM at: and a new verion of GPM at:
http://www.geocities.com/dt_or/gpm/gpm.html http://www.geocities.com/dt_or/gpm/gpm.html
to take advantage of the advanced features of the touchpad. to take advantage of the advanced features of the touchpad.
If you do not want install specialized drivers but want tapping
working please use option psmouse.proto=imps.
If unsure, say Y. If unsure, say Y.
......
...@@ -277,7 +277,7 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties) ...@@ -277,7 +277,7 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties)
protocol = PSMOUSE_PS2TPP; protocol = PSMOUSE_PS2TPP;
} }
} else if (get_model_info(model) != NULL) { } else if (model_info != NULL) {
param[0] = param[1] = param[2] = 0; param[0] = param[1] = param[2] = 0;
ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */ ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */
......
...@@ -48,8 +48,13 @@ static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y; ...@@ -48,8 +48,13 @@ static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y;
module_param(yres, uint, 0); module_param(yres, uint, 0);
MODULE_PARM_DESC(yres, "Vertical screen resolution"); MODULE_PARM_DESC(yres, "Vertical screen resolution");
static unsigned tap_time = 200;
module_param(tap_time, uint, 0);
MODULE_PARM_DESC(tap_time, "Tap time for touchpads in absolute mode (msecs)");
struct mousedev_motion { struct mousedev_motion {
int dx, dy, dz; int dx, dy, dz;
unsigned long buttons;
}; };
struct mousedev { struct mousedev {
...@@ -62,21 +67,31 @@ struct mousedev { ...@@ -62,21 +67,31 @@ struct mousedev {
struct input_handle handle; struct input_handle handle;
struct mousedev_motion packet; struct mousedev_motion packet;
unsigned long buttons;
unsigned int pkt_count; unsigned int pkt_count;
int old_x[4], old_y[4]; int old_x[4], old_y[4];
unsigned int touch; unsigned long touch;
}; };
enum mousedev_emul {
MOUSEDEV_EMUL_PS2,
MOUSEDEV_EMUL_IMPS,
MOUSEDEV_EMUL_EXPS
} __attribute__ ((packed));
#define PACKET_QUEUE_LEN 16
struct mousedev_list { struct mousedev_list {
struct fasync_struct *fasync; struct fasync_struct *fasync;
struct mousedev *mousedev; struct mousedev *mousedev;
struct list_head node; struct list_head node;
int dx, dy, dz;
unsigned long buttons; struct mousedev_motion packets[PACKET_QUEUE_LEN];
unsigned int head, tail;
spinlock_t packet_lock;
signed char ps2[6]; signed char ps2[6];
unsigned char ready, buffer, bufsiz; unsigned char ready, buffer, bufsiz;
unsigned char mode, imexseq, impsseq; unsigned char imexseq, impsseq;
enum mousedev_emul mode;
}; };
#define MOUSEDEV_SEQ_LEN 6 #define MOUSEDEV_SEQ_LEN 6
...@@ -165,30 +180,70 @@ static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int ...@@ -165,30 +180,70 @@ static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int
} }
if (value) { if (value) {
set_bit(index, &mousedev->buttons); set_bit(index, &mousedev->packet.buttons);
set_bit(index, &mousedev_mix.buttons); set_bit(index, &mousedev_mix.packet.buttons);
} else { } else {
clear_bit(index, &mousedev->buttons); clear_bit(index, &mousedev->packet.buttons);
clear_bit(index, &mousedev_mix.buttons); clear_bit(index, &mousedev_mix.packet.buttons);
} }
} }
static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_motion *packet) static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_motion *packet)
{ {
struct mousedev_list *list; struct mousedev_list *list;
struct mousedev_motion *p;
unsigned long flags;
list_for_each_entry(list, &mousedev->list, node) { list_for_each_entry(list, &mousedev->list, node) {
list->dx += packet->dx; spin_lock_irqsave(&list->packet_lock, flags);
list->dy += packet->dy;
list->dz += packet->dz; p = &list->packets[list->head];
list->buttons = mousedev->buttons; if (list->ready && p->buttons != packet->buttons) {
unsigned int new_head = (list->head + 1) % PACKET_QUEUE_LEN;
if (new_head != list->tail) {
p = &list->packets[list->head = new_head];
memset(p, 0, sizeof(struct mousedev_motion));
}
}
p->dx += packet->dx;
p->dy += packet->dy;
p->dz += packet->dz;
p->buttons = mousedev->packet.buttons;
list->ready = 1; list->ready = 1;
spin_unlock_irqrestore(&list->packet_lock, flags);
kill_fasync(&list->fasync, SIGIO, POLL_IN); kill_fasync(&list->fasync, SIGIO, POLL_IN);
} }
wake_up_interruptible(&mousedev->wait); wake_up_interruptible(&mousedev->wait);
} }
static void mousedev_touchpad_touch(struct mousedev *mousedev, int value)
{
if (!value) {
if (mousedev->touch &&
!time_after(jiffies, mousedev->touch + msecs_to_jiffies(tap_time))) {
/*
* 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);
set_bit(0, &mousedev_mix.packet.buttons);
mousedev_notify_readers(mousedev, &mousedev_mix.packet);
mousedev_notify_readers(&mousedev_mix, &mousedev_mix.packet);
clear_bit(0, &mousedev->packet.buttons);
clear_bit(0, &mousedev_mix.packet.buttons);
}
mousedev->touch = mousedev->pkt_count = 0;
}
else
if (!mousedev->touch)
mousedev->touch = jiffies;
}
static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{ {
struct mousedev *mousedev = handle->private; struct mousedev *mousedev = handle->private;
...@@ -212,12 +267,8 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig ...@@ -212,12 +267,8 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig
case EV_KEY: case EV_KEY:
if (value != 2) { if (value != 2) {
if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) { if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
/* Handle touchpad data */ mousedev_touchpad_touch(mousedev, value);
mousedev->touch = value;
if (!mousedev->touch)
mousedev->pkt_count = 0;
}
else else
mousedev_key_event(mousedev, code, value); mousedev_key_event(mousedev, code, value);
} }
...@@ -237,7 +288,7 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig ...@@ -237,7 +288,7 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig
mousedev_notify_readers(mousedev, &mousedev->packet); mousedev_notify_readers(mousedev, &mousedev->packet);
mousedev_notify_readers(&mousedev_mix, &mousedev->packet); mousedev_notify_readers(&mousedev_mix, &mousedev->packet);
memset(&mousedev->packet, 0, sizeof(struct mousedev_motion)); mousedev->packet.dx = mousedev->packet.dy = mousedev->packet.dz = 0;
} }
break; break;
} }
...@@ -322,6 +373,7 @@ static int mousedev_open(struct inode * inode, struct file * file) ...@@ -322,6 +373,7 @@ static int mousedev_open(struct inode * inode, struct file * file)
return -ENOMEM; return -ENOMEM;
memset(list, 0, sizeof(struct mousedev_list)); memset(list, 0, sizeof(struct mousedev_list));
spin_lock_init(&list->packet_lock);
list->mousedev = mousedev_table[i]; list->mousedev = mousedev_table[i];
list_add_tail(&list->node, &mousedev_table[i]->list); list_add_tail(&list->node, &mousedev_table[i]->list);
file->private_data = list; file->private_data = list;
...@@ -341,32 +393,56 @@ static int mousedev_open(struct inode * inode, struct file * file) ...@@ -341,32 +393,56 @@ static int mousedev_open(struct inode * inode, struct file * file)
return 0; return 0;
} }
static void mousedev_packet(struct mousedev_list *list, unsigned char off) static inline int mousedev_limit_delta(int delta, int limit)
{ {
list->ps2[off] = 0x08 | ((list->dx < 0) << 4) | ((list->dy < 0) << 5) | (list->buttons & 0x07); return delta > limit ? limit : (delta < -limit ? -limit : delta);
list->ps2[off + 1] = (list->dx > 127 ? 127 : (list->dx < -127 ? -127 : list->dx)); }
list->ps2[off + 2] = (list->dy > 127 ? 127 : (list->dy < -127 ? -127 : list->dy));
list->dx -= list->ps2[off + 1]; static void mousedev_packet(struct mousedev_list *list, signed char *ps2_data)
list->dy -= list->ps2[off + 2]; {
list->bufsiz = off + 3; struct mousedev_motion *p;
unsigned long flags;
if (list->mode == 2) {
list->ps2[off + 3] = (list->dz > 7 ? 7 : (list->dz < -7 ? -7 : list->dz)); spin_lock_irqsave(&list->packet_lock, flags);
list->dz -= list->ps2[off + 3]; p = &list->packets[list->tail];
list->ps2[off + 3] = (list->ps2[off + 3] & 0x0f) | ((list->buttons & 0x18) << 1);
list->bufsiz++; ps2_data[0] = 0x08 | ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07);
} else { ps2_data[1] = mousedev_limit_delta(p->dx, 127);
list->ps2[off] |= ((list->buttons & 0x10) >> 3) | ((list->buttons & 0x08) >> 1); ps2_data[2] = mousedev_limit_delta(p->dy, 127);
p->dx -= ps2_data[1];
p->dy -= ps2_data[2];
switch (list->mode) {
case MOUSEDEV_EMUL_EXPS:
ps2_data[3] = mousedev_limit_delta(p->dz, 127);
p->dz -= ps2_data[3];
ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1);
list->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];
list->bufsiz = 4;
break;
case MOUSEDEV_EMUL_PS2:
default:
ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
p->dz = 0;
list->bufsiz = 3;
break;
} }
if (list->mode == 1) { if (!p->dx && !p->dy && !p->dz) {
list->ps2[off + 3] = (list->dz > 127 ? 127 : (list->dz < -127 ? -127 : list->dz)); if (list->tail != list->head)
list->dz -= list->ps2[off + 3]; list->tail = (list->tail + 1) % PACKET_QUEUE_LEN;
list->bufsiz++; if (list->tail == list->head)
list->ready = 0;
} }
if (!list->dx && !list->dy && (!list->mode || !list->dz)) list->ready = 0; spin_unlock_irqrestore(&list->packet_lock, flags);
list->buffer = list->bufsiz;
} }
...@@ -384,31 +460,31 @@ static ssize_t mousedev_write(struct file * file, const char __user * buffer, si ...@@ -384,31 +460,31 @@ static ssize_t mousedev_write(struct file * file, const char __user * buffer, si
if (c == mousedev_imex_seq[list->imexseq]) { if (c == mousedev_imex_seq[list->imexseq]) {
if (++list->imexseq == MOUSEDEV_SEQ_LEN) { if (++list->imexseq == MOUSEDEV_SEQ_LEN) {
list->imexseq = 0; list->imexseq = 0;
list->mode = 2; list->mode = MOUSEDEV_EMUL_EXPS;
} }
} else list->imexseq = 0; } else list->imexseq = 0;
if (c == mousedev_imps_seq[list->impsseq]) { if (c == mousedev_imps_seq[list->impsseq]) {
if (++list->impsseq == MOUSEDEV_SEQ_LEN) { if (++list->impsseq == MOUSEDEV_SEQ_LEN) {
list->impsseq = 0; list->impsseq = 0;
list->mode = 1; list->mode = MOUSEDEV_EMUL_IMPS;
} }
} else list->impsseq = 0; } else list->impsseq = 0;
list->ps2[0] = 0xfa; list->ps2[0] = 0xfa;
list->bufsiz = 1;
switch (c) { switch (c) {
case 0xeb: /* Poll */ case 0xeb: /* Poll */
mousedev_packet(list, 1); mousedev_packet(list, &list->ps2[1]);
list->bufsiz++; /* account for leading ACK */
break; break;
case 0xf2: /* Get ID */ case 0xf2: /* Get ID */
switch (list->mode) { switch (list->mode) {
case 0: list->ps2[1] = 0; break; case MOUSEDEV_EMUL_PS2: list->ps2[1] = 0; break;
case 1: list->ps2[1] = 3; break; case MOUSEDEV_EMUL_IMPS: list->ps2[1] = 3; break;
case 2: list->ps2[1] = 4; break; case MOUSEDEV_EMUL_EXPS: list->ps2[1] = 4; break;
} }
list->bufsiz = 2; list->bufsiz = 2;
break; break;
...@@ -419,13 +495,15 @@ static ssize_t mousedev_write(struct file * file, const char __user * buffer, si ...@@ -419,13 +495,15 @@ static ssize_t mousedev_write(struct file * file, const char __user * buffer, si
break; break;
case 0xff: /* Reset */ case 0xff: /* Reset */
list->impsseq = 0; list->impsseq = list->imexseq = 0;
list->imexseq = 0; list->mode = MOUSEDEV_EMUL_PS2;
list->mode = 0; list->ps2[1] = 0xaa; list->ps2[2] = 0x00;
list->ps2[1] = 0xaa;
list->ps2[2] = 0x00;
list->bufsiz = 3; list->bufsiz = 3;
break; break;
default:
list->bufsiz = 1;
break;
} }
list->buffer = list->bufsiz; list->buffer = list->bufsiz;
...@@ -451,8 +529,10 @@ static ssize_t mousedev_read(struct file * file, char __user * buffer, size_t co ...@@ -451,8 +529,10 @@ static ssize_t mousedev_read(struct file * file, char __user * buffer, size_t co
if (retval) if (retval)
return retval; return retval;
if (!list->buffer && list->ready) if (!list->buffer && list->ready) {
mousedev_packet(list, 0); mousedev_packet(list, list->ps2);
list->buffer = list->bufsiz;
}
if (count > list->buffer) if (count > list->buffer)
count = list->buffer; count = list->buffer;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment