Commit aac0e012 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://kernel.bkbits.net/vojtech/input

into home.osdl.org:/home/torvalds/v2.5/linux
parents 157e3d70 0736b22a
......@@ -788,6 +788,10 @@ running once the system is up.
psmouse_noext [HW,MOUSE] Disable probing for PS2 mouse protocol extensions
psmouse_resetafter=
[HW,MOUSE] Try to reset Synaptics Touchpad after so many
bad packets (0 = never).
pss= [HW,OSS] Personal Sound System (ECHO ESC614)
Format: <io>,<mss_io>,<mss_irq>,<mss_dma>,<mpu_io>,<mpu_irq>
......
......@@ -205,7 +205,7 @@ int setkeycode(unsigned int scancode, unsigned int keycode)
INPUT_KEYCODE(dev, scancode) = keycode;
for (i = 0; i < dev->keycodemax; i++)
if(INPUT_KEYCODE(dev, scancode) == oldkey)
if(keycode == oldkey)
break;
if (i == dev->keycodemax)
clear_bit(oldkey, dev->keybit);
......
......@@ -208,7 +208,7 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
struct evdev *evdev = list->evdev;
struct input_dev *dev = evdev->handle.dev;
struct input_absinfo abs;
int i, t, u;
int i, t, u, v;
if (!evdev->exist) return -ENODEV;
......@@ -239,14 +239,12 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
case EVIOCSKEYCODE:
if (get_user(t, ((int *) arg) + 0)) return -EFAULT;
if (t < 0 || t > dev->keycodemax || !dev->keycodesize) return -EINVAL;
if (get_user(v, ((int *) arg) + 1)) return -EFAULT;
u = INPUT_KEYCODE(dev, t);
if (get_user(INPUT_KEYCODE(dev, t), ((int *) arg) + 1)) return -EFAULT;
for (i = 0; i < dev->keycodemax; i++)
if(INPUT_KEYCODE(dev, t) == u) break;
INPUT_KEYCODE(dev, t) = v;
for (i = 0; i < dev->keycodemax; i++) if (v == u) break;
if (i == dev->keycodemax) clear_bit(u, dev->keybit);
set_bit(INPUT_KEYCODE(dev, t), dev->keybit);
set_bit(v, dev->keybit);
return 0;
case EVIOCSFF:
......
......@@ -426,8 +426,10 @@ void input_register_device(struct input_dev *dev)
init_timer(&dev->timer);
dev->timer.data = (long) dev;
dev->timer.function = input_repeat_key;
dev->rep[REP_DELAY] = HZ/4;
dev->rep[REP_PERIOD] = HZ/33;
if (!dev->rep[REP_DELAY])
dev->rep[REP_DELAY] = HZ/4;
if (!dev->rep[REP_PERIOD])
dev->rep[REP_PERIOD] = HZ/33;
INIT_LIST_HEAD(&dev->h_list);
list_add_tail(&dev->node, &input_dev_list);
......
......@@ -55,7 +55,9 @@ MODULE_PARM(db9_3, "2i");
#define DB9_MULTI_0802 0x08
#define DB9_MULTI_0802_2 0x09
#define DB9_CD32_PAD 0x0A
#define DB9_MAX_PAD 0x0B
#define DB9_SATURN_DPP 0x0B
#define DB9_SATURN_DPP_2 0x0C
#define DB9_MAX_PAD 0x0D
#define DB9_UP 0x01
#define DB9_DOWN 0x02
......@@ -69,10 +71,7 @@ MODULE_PARM(db9_3, "2i");
#define DB9_NORMAL 0x0a
#define DB9_NOSELECT 0x08
#define DB9_SATURN0 0x00
#define DB9_SATURN1 0x02
#define DB9_SATURN2 0x04
#define DB9_SATURN3 0x06
#define DB9_MAX_DEVICES 2
#define DB9_GENESIS6_DELAY 14
#define DB9_REFRESH_TIME HZ/100
......@@ -82,7 +81,7 @@ static int db9_2[] __initdata = { -1, 0 };
static int db9_3[] __initdata = { -1, 0 };
struct db9 {
struct input_dev dev[2];
struct input_dev dev[DB9_MAX_DEVICES];
struct timer_list timer;
struct pardevice *pd;
int mode;
......@@ -96,12 +95,247 @@ static short db9_multi_btn[] = { BTN_TRIGGER, BTN_THUMB };
static short db9_genesis_btn[] = { BTN_START, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_MODE };
static short db9_cd32_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START };
static char db9_buttons[DB9_MAX_PAD] = { 0, 1, 2, 4, 0, 6, 8, 8, 1, 1, 7 };
static char db9_buttons[DB9_MAX_PAD] = { 0, 1, 2, 4, 0, 6, 8, 9, 1, 1, 7, 9, 9 };
static short *db9_btn[DB9_MAX_PAD] = { NULL, db9_multi_btn, db9_multi_btn, db9_genesis_btn, NULL, db9_genesis_btn,
db9_genesis_btn, db9_cd32_btn, db9_multi_btn, db9_multi_btn, db9_cd32_btn };
db9_genesis_btn, db9_cd32_btn, db9_multi_btn, db9_multi_btn, db9_cd32_btn,
db9_cd32_btn, db9_cd32_btn };
static char *db9_name[DB9_MAX_PAD] = { NULL, "Multisystem joystick", "Multisystem joystick (2 fire)", "Genesis pad",
NULL, "Genesis 5 pad", "Genesis 6 pad", "Saturn pad", "Multisystem (0.8.0.2) joystick",
"Multisystem (0.8.0.2-dual) joystick", "Amiga CD-32 pad" };
"Multisystem (0.8.0.2-dual) joystick", "Amiga CD-32 pad", "Saturn dpp", "Saturn dpp dual" };
static const int db9_max_pads[DB9_MAX_PAD] = { 0, 1, 1, 1, 0, 1, 1, 6, 1, 2, 1, 6, 12 };
static const int db9_num_axis[DB9_MAX_PAD] = { 0, 2, 2, 2, 0, 2, 2, 7, 2, 2, 2 ,7, 7 };
static const short db9_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_RZ, ABS_Z, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y };
static const int db9_bidirectional[DB9_MAX_PAD] = { 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0 };
static const int db9_reverse[DB9_MAX_PAD] = { 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0 };
/*
* Saturn controllers
*/
#define DB9_SATURN_DELAY 300
static const int db9_saturn_byte[] = { 1, 1, 1, 2, 2, 2, 2, 2, 1 };
static const unsigned char db9_saturn_mask[] = { 0x04, 0x01, 0x02, 0x40, 0x20, 0x10, 0x08, 0x80, 0x08 };
/*
* db9_saturn_write_sub() writes 2 bit data.
*/
static void db9_saturn_write_sub(struct parport *port, int type, unsigned char data, int powered, int pwr_sub)
{
unsigned char c;
switch (type) {
case 1: /* DPP1 */
c = 0x80 | 0x30 | (powered ? 0x08 : 0) | (pwr_sub ? 0x04 : 0) | data;
parport_write_data(port, c);
break;
case 2: /* DPP2 */
c = 0x40 | data << 4 | (powered ? 0x08 : 0) | (pwr_sub ? 0x04 : 0) | 0x03;
parport_write_data(port, c);
break;
case 0: /* DB9 */
c = ((((data & 2) ? 2 : 0) | ((data & 1) ? 4 : 0)) ^ 0x02) | !powered;
parport_write_control(port, c);
break;
}
}
/*
* gc_saturn_read_sub() reads 4 bit data.
*/
static unsigned char db9_saturn_read_sub(struct parport *port, int type)
{
unsigned char data;
if (type) {
/* DPP */
data = parport_read_status(port) ^ 0x80;
return (data & 0x80 ? 1 : 0) | (data & 0x40 ? 2 : 0)
| (data & 0x20 ? 4 : 0) | (data & 0x10 ? 8 : 0);
} else {
/* DB9 */
data = parport_read_data(port) & 0x0f;
return (data & 0x8 ? 1 : 0) | (data & 0x4 ? 2 : 0)
| (data & 0x2 ? 4 : 0) | (data & 0x1 ? 8 : 0);
}
}
/*
* db9_saturn_read_analog() sends clock and reads 8 bit data.
*/
static unsigned char db9_saturn_read_analog(struct parport *port, int type, int powered)
{
unsigned char data;
db9_saturn_write_sub(port, type, 0, powered, 0);
udelay(DB9_SATURN_DELAY);
data = db9_saturn_read_sub(port, type) << 4;
db9_saturn_write_sub(port, type, 2, powered, 0);
udelay(DB9_SATURN_DELAY);
data |= db9_saturn_read_sub(port, type);
return data;
}
/*
* db9_saturn_read_packet() reads whole saturn packet at connector
* and returns device identifier code.
*/
static unsigned char db9_saturn_read_packet(struct parport *port, unsigned char *data, int type, int powered)
{
int i, j;
unsigned char tmp;
db9_saturn_write_sub(port, type, 3, powered, 0);
data[0] = db9_saturn_read_sub(port, type);
switch (data[0] & 0x0f) {
case 0xf:
/* 1111 no pad */
return data[0] = 0xff;
case 0x4: case 0x4 | 0x8:
/* ?100 : digital controller */
db9_saturn_write_sub(port, type, 0, powered, 1);
data[2] = db9_saturn_read_sub(port, type) << 4;
db9_saturn_write_sub(port, type, 2, powered, 1);
data[1] = db9_saturn_read_sub(port, type) << 4;
db9_saturn_write_sub(port, type, 1, powered, 1);
data[1] |= db9_saturn_read_sub(port, type);
db9_saturn_write_sub(port, type, 3, powered, 1);
/* data[2] |= db9_saturn_read_sub(port, type); */
data[2] |= data[0];
return data[0] = 0x02;
case 0x1:
/* 0001 : analog controller or multitap */
db9_saturn_write_sub(port, type, 2, powered, 0);
udelay(DB9_SATURN_DELAY);
data[0] = db9_saturn_read_analog(port, type, powered);
if (data[0] != 0x41) {
/* read analog controller */
for (i = 0; i < (data[0] & 0x0f); i++)
data[i + 1] = db9_saturn_read_analog(port, type, powered);
db9_saturn_write_sub(port, type, 3, powered, 0);
return data[0];
} else {
/* read multitap */
if (db9_saturn_read_analog(port, type, powered) != 0x60)
return data[0] = 0xff;
for (i = 0; i < 60; i += 10) {
data[i] = db9_saturn_read_analog(port, type, powered);
if (data[i] != 0xff)
/* read each pad */
for (j = 0; j < (data[i] & 0x0f); j++)
data[i + j + 1] = db9_saturn_read_analog(port, type, powered);
}
db9_saturn_write_sub(port, type, 3, powered, 0);
return 0x41;
}
case 0x0:
/* 0000 : mouse */
db9_saturn_write_sub(port, type, 2, powered, 0);
udelay(DB9_SATURN_DELAY);
tmp = db9_saturn_read_analog(port, type, powered);
if (tmp == 0xff) {
for (i = 0; i < 3; i++)
data[i + 1] = db9_saturn_read_analog(port, type, powered);
db9_saturn_write_sub(port, type, 3, powered, 0);
return data[0] = 0xe3;
}
default:
return data[0];
}
}
/*
* db9_saturn_report() analyzes packet and reports.
*/
static int db9_saturn_report(unsigned char id, unsigned char data[60], struct input_dev *dev, int n, int max_pads)
{
int tmp, i, j;
tmp = (id == 0x41) ? 60 : 10;
for (j = 0; (j < tmp) && (n < max_pads); j += 10, n++) {
switch (data[j]) {
case 0x16: /* multi controller (analog 4 axis) */
input_report_abs(dev + n, db9_abs[5], data[j + 6]);
case 0x15: /* mission stick (analog 3 axis) */
input_report_abs(dev + n, db9_abs[3], data[j + 4]);
input_report_abs(dev + n, db9_abs[4], data[j + 5]);
case 0x13: /* racing controller (analog 1 axis) */
input_report_abs(dev + n, db9_abs[2], data[j + 3]);
case 0x34: /* saturn keyboard (udlr ZXC ASD QE Esc) */
case 0x02: /* digital pad (digital 2 axis + buttons) */
input_report_abs(dev + n, db9_abs[0], !(data[j + 1] & 128) - !(data[j + 1] & 64));
input_report_abs(dev + n, db9_abs[1], !(data[j + 1] & 32) - !(data[j + 1] & 16));
for (i = 0; i < 9; i++)
input_report_key(dev + n, db9_cd32_btn[i], ~data[j + db9_saturn_byte[i]] & db9_saturn_mask[i]);
break;
case 0x19: /* mission stick x2 (analog 6 axis + buttons) */
input_report_abs(dev + n, db9_abs[0], !(data[j + 1] & 128) - !(data[j + 1] & 64));
input_report_abs(dev + n, db9_abs[1], !(data[j + 1] & 32) - !(data[j + 1] & 16));
for (i = 0; i < 9; i++)
input_report_key(dev + n, db9_cd32_btn[i], ~data[j + db9_saturn_byte[i]] & db9_saturn_mask[i]);
input_report_abs(dev + n, db9_abs[2], data[j + 3]);
input_report_abs(dev + n, db9_abs[3], data[j + 4]);
input_report_abs(dev + n, db9_abs[4], data[j + 5]);
/*
input_report_abs(dev + n, db9_abs[8], (data[j + 6] & 128 ? 0 : 1) - (data[j + 6] & 64 ? 0 : 1));
input_report_abs(dev + n, db9_abs[9], (data[j + 6] & 32 ? 0 : 1) - (data[j + 6] & 16 ? 0 : 1));
*/
input_report_abs(dev + n, db9_abs[6], data[j + 7]);
input_report_abs(dev + n, db9_abs[7], data[j + 8]);
input_report_abs(dev + n, db9_abs[5], data[j + 9]);
break;
case 0xd3: /* sankyo ff (analog 1 axis + stop btn) */
input_report_key(dev + n, BTN_A, data[j + 3] & 0x80);
input_report_abs(dev + n, db9_abs[2], data[j + 3] & 0x7f);
break;
case 0xe3: /* shuttle mouse (analog 2 axis + buttons. signed value) */
input_report_key(dev + n, BTN_START, data[j + 1] & 0x08);
input_report_key(dev + n, BTN_A, data[j + 1] & 0x04);
input_report_key(dev + n, BTN_C, data[j + 1] & 0x02);
input_report_key(dev + n, BTN_B, data[j + 1] & 0x01);
input_report_abs(dev + n, db9_abs[2], data[j + 2] ^ 0x80);
input_report_abs(dev + n, db9_abs[3], (0xff-(data[j + 3] ^ 0x80))+1); /* */
break;
case 0xff:
default: /* no pad */
input_report_abs(dev + n, db9_abs[0], 0);
input_report_abs(dev + n, db9_abs[1], 0);
for (i = 0; i < 9; i++)
input_report_key(dev + n, db9_cd32_btn[i], 0);
break;
}
}
return n;
}
static int db9_saturn(int mode, struct parport *port, struct input_dev *dev)
{
unsigned char id, data[60];
int type, n, max_pads;
int tmp, i;
switch (mode) {
case DB9_SATURN_PAD:
type = 0;
n = 1;
break;
case DB9_SATURN_DPP:
type = 1;
n = 1;
break;
case DB9_SATURN_DPP_2:
type = 1;
n = 2;
break;
default:
return -1;
}
max_pads = min(db9_max_pads[mode], DB9_MAX_DEVICES);
for (tmp = 0, i = 0; i < n; i++) {
id = db9_saturn_read_packet(port, data, type + i, 1);
tmp = db9_saturn_report(id, data, dev, tmp, max_pads);
}
return 0;
}
static void db9_timer(unsigned long private)
{
......@@ -222,28 +456,10 @@ static void db9_timer(unsigned long private)
break;
case DB9_SATURN_PAD:
case DB9_SATURN_DPP:
case DB9_SATURN_DPP_2:
parport_write_control(port, DB9_SATURN0);
data = parport_read_data(port);
input_report_key(dev, BTN_Y, ~data & DB9_LEFT);
input_report_key(dev, BTN_Z, ~data & DB9_DOWN);
input_report_key(dev, BTN_TL, ~data & DB9_UP);
input_report_key(dev, BTN_TR, ~data & DB9_RIGHT);
parport_write_control(port, DB9_SATURN2);
data = parport_read_data(port);
input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
parport_write_control(port, DB9_NORMAL);
data = parport_read_data(port);
input_report_key(dev, BTN_A, ~data & DB9_LEFT);
input_report_key(dev, BTN_B, ~data & DB9_UP);
input_report_key(dev, BTN_C, ~data & DB9_DOWN);
input_report_key(dev, BTN_X, ~data & DB9_RIGHT);
db9_saturn(db9->mode, port, dev);
break;
case DB9_CD32_PAD:
......@@ -279,8 +495,10 @@ static int db9_open(struct input_dev *dev)
if (!db9->used++) {
parport_claim(db9->pd);
parport_write_data(port, 0xff);
parport_data_reverse(port);
parport_write_control(port, DB9_NORMAL);
if (db9_reverse[db9->mode]) {
parport_data_reverse(port);
parport_write_control(port, DB9_NORMAL);
}
mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
}
......@@ -321,11 +539,13 @@ static struct db9 __init *db9_probe(int *config)
return NULL;
}
if (!(pp->modes & PARPORT_MODE_TRISTATE) && config[1] != DB9_MULTI_0802) {
printk(KERN_ERR "db9.c: specified parport is not bidirectional\n");
return NULL;
if (db9_bidirectional[config[1]]) {
if (!(pp->modes & PARPORT_MODE_TRISTATE)) {
printk(KERN_ERR "db9.c: specified parport is not bidirectional\n");
return NULL;
}
}
if (!(db9 = kmalloc(sizeof(struct db9), GFP_KERNEL)))
return NULL;
memset(db9, 0, sizeof(struct db9));
......@@ -343,7 +563,7 @@ static struct db9 __init *db9_probe(int *config)
return NULL;
}
for (i = 0; i < 1 + (db9->mode == DB9_MULTI_0802_2); i++) {
for (i = 0; i < (min(db9_max_pads[db9->mode], DB9_MAX_DEVICES)); i++) {
sprintf(db9->phys[i], "%s/input%d", db9->pd->port->name, i);
......@@ -359,14 +579,19 @@ static struct db9 __init *db9_probe(int *config)
db9->dev[i].id.version = 0x0100;
db9->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
db9->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
for (j = 0; j < db9_buttons[db9->mode]; j++)
set_bit(db9_btn[db9->mode][j], db9->dev[i].keybit);
db9->dev[i].absmin[ABS_X] = -1; db9->dev[i].absmax[ABS_X] = 1;
db9->dev[i].absmin[ABS_Y] = -1; db9->dev[i].absmax[ABS_Y] = 1;
for (j = 0; j < db9_num_axis[db9->mode]; j++) {
set_bit(db9_abs[j], db9->dev[i].absbit);
if (j < 2) {
db9->dev[i].absmin[db9_abs[j]] = -1;
db9->dev[i].absmax[db9_abs[j]] = 1;
} else {
db9->dev[i].absmin[db9_abs[j]] = 1;
db9->dev[i].absmax[db9_abs[j]] = 255;
db9->dev[i].absflat[db9_abs[j]] = 0;
}
}
input_register_device(db9->dev + i);
printk(KERN_INFO "input: %s on %s\n", db9->dev[i].name, db9->pd->port->name);
}
......@@ -419,7 +644,7 @@ void __exit db9_exit(void)
for (i = 0; i < 3; i++)
if (db9_base[i]) {
for (j = 0; j < 1 + (db9_base[i]->mode == DB9_MULTI_0802_2); j++)
for (j = 0; j < min(db9_max_pads[db9_base[i]->mode], DB9_MAX_DEVICES); j++)
input_unregister_device(db9_base[i]->dev + j);
parport_unregister_device(db9_base[i]->pd);
}
......
......@@ -166,8 +166,7 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data,
iforce->expect_packet = 0;
iforce->ecmd = cmd;
memcpy(iforce->edata, data, IFORCE_MAX_LENGTH);
if (waitqueue_active(&iforce->wait))
wake_up(&iforce->wait);
wake_up(&iforce->wait);
}
#endif
......@@ -264,7 +263,7 @@ int iforce_get_id_packet(struct iforce *iforce, char *packet)
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&iforce->wait, &wait);
if (usb_submit_urb(iforce->ctrl, GFP_KERNEL)) {
if (usb_submit_urb(iforce->ctrl, GFP_ATOMIC)) {
set_current_state(TASK_RUNNING);
remove_wait_queue(&iforce->wait, &wait);
return -1;
......
......@@ -116,8 +116,7 @@ static void iforce_usb_out(struct urb *urb, struct pt_regs *regs)
iforce_usb_xmit(iforce);
if (waitqueue_active(&iforce->wait))
wake_up(&iforce->wait);
wake_up(&iforce->wait);
}
static void iforce_usb_ctrl(struct urb *urb, struct pt_regs *regs)
......@@ -125,8 +124,7 @@ static void iforce_usb_ctrl(struct urb *urb, struct pt_regs *regs)
struct iforce *iforce = urb->context;
if (urb->status) return;
iforce->ecmd = 0xff00 | urb->actual_length;
if (waitqueue_active(&iforce->wait))
wake_up(&iforce->wait);
wake_up(&iforce->wait);
}
static int iforce_usb_probe(struct usb_interface *intf,
......
......@@ -13,7 +13,8 @@ config INPUT_KEYBOARD
config KEYBOARD_ATKBD
tristate "AT keyboard support" if EMBEDDED || !X86
default y
default y if INPUT=y && INPUT_KEYBOARD=y && SERIO=y
default m
depends on INPUT && INPUT_KEYBOARD && SERIO
help
Say Y here if you want to use a standard AT or PS/2 keyboard. Usually
......
......@@ -18,6 +18,7 @@
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/workqueue.h>
#include <linux/timer.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("AT and PS/2 keyboard driver");
......@@ -40,8 +41,8 @@ static int atkbd_reset = 1;
static unsigned char atkbd_set2_keycode[512] = {
0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41, 85,
0, 56, 42,182, 29, 16, 2, 89, 0, 0, 44, 31, 30, 17, 3, 90,
0, 46, 45, 32, 18, 5, 4, 91, 0, 57, 47, 33, 20, 19, 6, 0,
0, 49, 48, 35, 34, 21, 7, 0, 0, 0, 50, 36, 22, 8, 9, 0,
0, 46, 45, 32, 18, 5, 4, 91, 90, 57, 47, 33, 20, 19, 6, 0,
91, 49, 48, 35, 34, 21, 7, 0, 0, 0, 50, 36, 22, 8, 9, 0,
0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0,
122, 89, 40,120, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 0,
85, 86, 90, 91, 92, 93, 14, 94, 95, 79,183, 75, 71,121, 0,123,
......@@ -87,10 +88,10 @@ static unsigned char atkbd_set3_keycode[512] = {
#define ATKBD_CMD_GSCANSET 0x11f0
#define ATKBD_CMD_SSCANSET 0x10f0
#define ATKBD_CMD_GETID 0x02f2
#define ATKBD_CMD_SETREP 0x10f3
#define ATKBD_CMD_ENABLE 0x00f4
#define ATKBD_CMD_RESET_DIS 0x00f5
#define ATKBD_CMD_RESET_BAT 0x02ff
#define ATKBD_CMD_SETALL_MB 0x00f8
#define ATKBD_CMD_RESEND 0x00fe
#define ATKBD_CMD_EX_ENABLE 0x10ea
#define ATKBD_CMD_EX_SETLEDS 0x20eb
......@@ -114,12 +115,14 @@ struct atkbd {
unsigned char keycode[512];
struct input_dev dev;
struct serio *serio;
struct timer_list timer;
char name[64];
char phys[32];
unsigned char cmdbuf[4];
unsigned char cmdcnt;
unsigned char set;
unsigned char release;
int lastkey;
volatile signed char ack;
unsigned char emul;
unsigned short id;
......@@ -142,6 +145,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
printk(KERN_DEBUG "atkbd.c: Received %02x flags %02x\n", data, flags);
#endif
#if !defined(__i386__) && !defined (__x86_64__)
if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && !atkbd->resend && atkbd->write) {
printk("atkbd.c: frame/parity error: %02x\n", flags);
serio_write(serio, ATKBD_CMD_RESEND);
......@@ -151,6 +155,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
if (!flags)
atkbd->resend = 0;
#endif
switch (code) {
case ATKBD_RET_ACK:
......@@ -195,6 +200,14 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
atkbd->set, code, serio->phys, atkbd->release ? "released" : "pressed");
break;
default:
if (!atkbd->release) {
mod_timer(&atkbd->timer,
jiffies + (test_bit(atkbd->keycode[code],
&atkbd->dev.key) ? HZ/33 : HZ/4) + HZ/100);
atkbd->lastkey = atkbd->keycode[code];
}
input_regs(&atkbd->dev, regs);
input_report_key(&atkbd->dev, atkbd->keycode[code], !atkbd->release);
input_sync(&atkbd->dev);
......@@ -205,6 +218,13 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
return IRQ_HANDLED;
}
static void atkbd_force_key_up(unsigned long data)
{
struct atkbd *atkbd = (void *) data;
input_report_key(&atkbd->dev, atkbd->lastkey, 0);
input_sync(&atkbd->dev);
}
/*
* atkbd_sendbyte() sends a byte to the keyboard, and waits for
* acknowledge. It doesn't handle resends according to the keyboard
......@@ -214,7 +234,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
static int atkbd_sendbyte(struct atkbd *atkbd, unsigned char byte)
{
int timeout = 10000; /* 100 msec */
int timeout = 20000; /* 200 msec */
atkbd->ack = 0;
#ifdef ATKBD_DEBUG
......@@ -322,13 +342,50 @@ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int co
}
/*
* Enable keyboard.
* atkbd_probe() probes for an AT keyboard on a serio port.
*/
static void atkbd_enable(struct atkbd *atkbd)
static int atkbd_probe(struct atkbd *atkbd)
{
if (atkbd_command(atkbd, NULL, ATKBD_CMD_ENABLE))
printk(KERN_ERR "atkbd.c: Failed to enable keyboard on %s\n",
atkbd->serio->phys);
unsigned char param[2];
/*
* Some systems, where the bit-twiddling when testing the io-lines of the
* controller may confuse the keyboard need a full reset of the keyboard. On
* these systems the BIOS also usually doesn't do it for us.
*/
if (atkbd_reset)
if (atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_BAT))
printk(KERN_WARNING "atkbd.c: keyboard reset failed on %s\n", atkbd->serio->phys);
/*
* Then we check the keyboard ID. We should get 0xab83 under normal conditions.
* Some keyboards report different values, but the first byte is always 0xab or
* 0xac. Some old AT keyboards don't report anything. If a mouse is connected, this
* should make sure we don't try to set the LEDs on it.
*/
if (atkbd_command(atkbd, param, ATKBD_CMD_GETID)) {
/*
* If the get ID command failed, we check if we can at least set the LEDs on
* the keyboard. This should work on every keyboard out there. It also turns
* the LEDs off, which we want anyway.
*/
param[0] = 0;
if (atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS))
return -1;
atkbd->id = 0xabba;
return 0;
}
if (param[0] != 0xab && param[0] != 0xac)
return -1;
atkbd->id = (param[0] << 8) | param[1];
return 0;
}
/*
......@@ -365,102 +422,56 @@ static int atkbd_set_3(struct atkbd *atkbd)
return 4;
}
/*
* Try to set the set we want.
*/
if (atkbd_set != 3)
return 2;
param[0] = atkbd_set;
param[0] = 3;
if (atkbd_command(atkbd, param, ATKBD_CMD_SSCANSET))
return 2;
/*
* Read set number. Beware here. Some keyboards always send '2'
* or some other number regardless into what mode they have been
* attempted to be set. Other keyboards treat the '0' command as
* 'set to set 0', and not 'report current set' as they should.
* In that case we time out, and return 2.
*/
param[0] = 0;
if (atkbd_command(atkbd, param, ATKBD_CMD_GSCANSET))
return 2;
/*
* Here we return the set number the keyboard reports about
* itself.
*/
if (param[0] != 3)
return 2;
return (param[0] == 3) ? 3 : 2;
return 3;
}
/*
* atkbd_probe() probes for an AT keyboard on a serio port.
*/
static int atkbd_probe(struct atkbd *atkbd)
static int atkbd_enable(struct atkbd *atkbd)
{
unsigned char param[2];
/*
* Some systems, where the bit-twiddling when testing the io-lines of the
* controller may confuse the keyboard need a full reset of the keyboard. On
* these systems the BIOS also usually doesn't do it for us.
*/
if (atkbd_reset)
if (atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_BAT))
printk(KERN_WARNING
"atkbd.c: keyboard reset failed on %s\n",
atkbd->serio->phys);
unsigned char param[1];
/*
* Then we check the keyboard ID. We should get 0xab83 under normal conditions.
* Some keyboards report different values, but the first byte is always 0xab or
* 0xac. Some old AT keyboards don't report anything.
* Set the LEDs to a defined state.
*/
if (atkbd_command(atkbd, param, ATKBD_CMD_GETID)) {
param[0] = 0;
if (atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS))
return -1;
/*
* If the get ID command failed, we check if we can at least set the LEDs on
* the keyboard. This should work on every keyboard out there. It also turns
* the LEDs off, which we want anyway.
* Set autorepeat to fastest possible.
*/
param[0] = 0;
if (atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS))
return -1;
atkbd->id = 0xabba;
return 0;
}
if (param[0] != 0xab && param[0] != 0xac)
param[0] = 0;
if (atkbd_command(atkbd, param, ATKBD_CMD_SETREP))
return -1;
atkbd->id = (param[0] << 8) | param[1];
/*
* Set the LEDs to a defined state.
* Enable the keyboard to receive keystrokes.
*/
param[0] = 0;
if (atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS))
if (atkbd_command(atkbd, NULL, ATKBD_CMD_ENABLE)) {
printk(KERN_ERR "atkbd.c: Failed to enable keyboard on %s\n",
atkbd->serio->phys);
return -1;
}
return 0;
}
/*
* Disable autorepeat. We don't need it, as we do it in software anyway,
* because that way can get faster repeat, and have less system load (less
* accesses to the slow ISA hardware). If this fails, we don't care, and will
* just ignore the repeated keys.
*
* This command is for scancode set 3 only.
*/
static void atkbd_disable_autorepeat(struct atkbd *atkbd)
{
atkbd_command(atkbd, NULL, ATKBD_CMD_SETALL_MB);
}
/*
* atkbd_cleanup() restores the keyboard state so that BIOS is happy after a
* reboot.
......@@ -485,7 +496,7 @@ static void atkbd_disconnect(struct serio *serio)
}
/*
* atkbd_connect() is called when the serio module finds an interface
* atkbd_connect() is called when the serio module finds and interface
* that isn't handled yet by an appropriate device driver. We check if
* there is an AT keyboard out there and if yes, we register ourselves
* to the input module.
......@@ -513,6 +524,9 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
atkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
} else atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
atkbd->dev.rep[REP_DELAY] = HZ/4 + HZ/50;
atkbd->dev.rep[REP_PERIOD] = HZ/33;
atkbd->serio = serio;
init_input_dev(&atkbd->dev);
......@@ -525,6 +539,10 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
serio->private = atkbd;
init_timer(&atkbd->timer);
atkbd->timer.data = (long) atkbd;
atkbd->timer.function = atkbd_force_key_up;
if (serio_open(serio, dev)) {
kfree(atkbd);
return;
......@@ -539,9 +557,8 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
}
atkbd->set = atkbd_set_3(atkbd);
if (atkbd->set == 3)
atkbd_disable_autorepeat(atkbd);
atkbd_enable(atkbd);
} else {
atkbd->set = 2;
atkbd->id = 0xab00;
......
......@@ -19,9 +19,7 @@ config MOUSE_PS2
Say Y here if you have a PS/2 mouse connected to your system. This
includes the standard 2 or 3-button PS/2 mouse, as well as PS/2
mice with wheels and extra buttons, Microsoft, Logitech or Genius
compatible. Support for Synaptics TouchPads is also included.
For Synaptics TouchPad support in XFree86 you'll need this XFree86
driver: http://w1.894.telia.com/~u89404340/touchpad/index.html
compatible.
If unsure, say Y.
......@@ -30,6 +28,22 @@ config MOUSE_PS2
The module will be called psmouse. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
config MOUSE_PS2_SYNAPTICS
bool "Synaptics TouchPad"
default n
depends on INPUT && INPUT_MOUSE && SERIO && MOUSE_PS2
---help---
Say Y here if you have a Synaptics TouchPad connected to your system.
This touchpad is found on many modern laptop computers.
Note that you also need a user space driver to interpret the data
generated by the kernel. A compatible driver for XFree86 is available
from http://w1.894.telia.com/~u89404340/touchpad/index.html
The gpm program is not yet able to interpret the data from this
driver, so if you need to use the touchpad in the console, you have to
say N for now.
config MOUSE_SERIAL
tristate "Serial mouse"
depends on INPUT && INPUT_MOUSE && SERIO
......
......@@ -17,6 +17,7 @@
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/init.h>
#include <linux/pm.h>
#include "psmouse.h"
#include "synaptics.h"
#include "logips2pp.h"
......@@ -29,6 +30,8 @@ MODULE_PARM(psmouse_resolution, "i");
MODULE_PARM_DESC(psmouse_resolution, "Resolution, in dpi.");
MODULE_PARM(psmouse_smartscroll, "i");
MODULE_PARM_DESC(psmouse_smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled.");
MODULE_PARM(psmouse_resetafter, "i");
MODULE_PARM_DESC(psmouse_resetafter, "Reset Synaptics Touchpad after so many bad packets (0 = never).");
MODULE_LICENSE("GPL");
#define PSMOUSE_LOGITECH_SMARTSCROLL 1
......@@ -36,11 +39,12 @@ MODULE_LICENSE("GPL");
static int psmouse_noext;
int psmouse_resolution;
int psmouse_smartscroll = PSMOUSE_LOGITECH_SMARTSCROLL;
unsigned int psmouse_resetafter;
static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "Synaptics"};
static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2"};
/*
* psmouse_process_packet() anlyzes the PS/2 mouse packet contents and
* psmouse_process_packet() analyzes the PS/2 mouse packet contents and
* reports relevant events to the input module.
*/
......@@ -108,6 +112,9 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
{
struct psmouse *psmouse = serio->private;
if (psmouse->state == PSMOUSE_IGNORE)
goto out;
if (psmouse->acking) {
switch (data) {
case PSMOUSE_RET_ACK:
......@@ -132,20 +139,35 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
}
if (psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) {
printk(KERN_WARNING "psmouse.c: Lost synchronization, throwing %d bytes away.\n", psmouse->pktcnt);
printk(KERN_WARNING "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n",
psmouse->name, psmouse->phys, psmouse->pktcnt);
psmouse->pktcnt = 0;
}
psmouse->last = jiffies;
psmouse->packet[psmouse->pktcnt++] = data;
if (psmouse->pktcnt == 3 + (psmouse->type >= PSMOUSE_GENPS)) {
psmouse_process_packet(psmouse, regs);
psmouse->pktcnt = 0;
goto out;
if (psmouse->packet[0] == PSMOUSE_RET_BAT) {
if (psmouse->pktcnt == 1)
goto out;
if (psmouse->pktcnt == 2) {
if (psmouse->packet[1] == PSMOUSE_RET_ID) {
psmouse->state = PSMOUSE_IGNORE;
serio_rescan(serio);
goto out;
}
if (psmouse->type == PSMOUSE_SYNAPTICS) {
/* neither 0xAA nor 0x00 are valid first bytes
* for a packet in absolute mode
*/
psmouse->pktcnt = 0;
goto out;
}
}
}
if (psmouse->pktcnt == 1 && psmouse->type == PSMOUSE_SYNAPTICS) {
if (psmouse->type == PSMOUSE_SYNAPTICS) {
/*
* The synaptics driver has its own resync logic,
* so it needs to receive all bytes one at a time.
......@@ -155,8 +177,9 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
goto out;
}
if (psmouse->pktcnt == 1 && psmouse->packet[0] == PSMOUSE_RET_BAT) {
serio_rescan(serio);
if (psmouse->pktcnt == 3 + (psmouse->type >= PSMOUSE_GENPS)) {
psmouse_process_packet(psmouse, regs);
psmouse->pktcnt = 0;
goto out;
}
out:
......@@ -200,7 +223,7 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command)
psmouse->cmdcnt = receive;
if (command == PSMOUSE_CMD_RESET_BAT)
timeout = 2000000; /* 2 sec */
timeout = 4000000; /* 4 sec */
if (command & 0xff)
if (psmouse_sendbyte(psmouse, command & 0xff))
......@@ -227,7 +250,7 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command)
for (i = 0; i < receive; i++)
param[i] = psmouse->cmdbuf[(receive - 1) - i];
if (psmouse->cmdcnt)
if (psmouse->cmdcnt)
return (psmouse->cmdcnt = 0) - 1;
return 0;
......@@ -450,14 +473,18 @@ static void psmouse_initialize(struct psmouse *psmouse)
*/
psmouse_command(psmouse, param, PSMOUSE_CMD_SETSTREAM);
}
/*
* Last, we enable the mouse so that we get reports from it.
* psmouse_activate() enables the mouse so that we get motion reports from it.
*/
static void psmouse_activate(struct psmouse *psmouse)
{
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE))
printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n", psmouse->serio->phys);
psmouse->state = PSMOUSE_ACTIVATED;
}
/*
......@@ -478,12 +505,38 @@ static void psmouse_cleanup(struct serio *serio)
static void psmouse_disconnect(struct serio *serio)
{
struct psmouse *psmouse = serio->private;
psmouse->state = PSMOUSE_IGNORE;
synaptics_disconnect(psmouse);
input_unregister_device(&psmouse->dev);
serio_close(serio);
synaptics_disconnect(psmouse);
kfree(psmouse);
}
/*
* Reinitialize mouse hardware after software suspend.
*/
static int psmouse_pm_callback(struct pm_dev *dev, pm_request_t request, void *data)
{
struct psmouse *psmouse = dev->data;
struct serio_dev *ser_dev = psmouse->serio->dev;
synaptics_disconnect(psmouse);
/* We need to reopen the serio port to reinitialize the i8042 controller */
serio_close(psmouse->serio);
serio_open(psmouse->serio, ser_dev);
/* Probe and re-initialize the mouse */
psmouse_probe(psmouse);
psmouse_initialize(psmouse);
synaptics_pt_init(psmouse);
psmouse_activate(psmouse);
return 0;
}
/*
* psmouse_connect() is a callback from the serio module when
* an unhandled serio port is found.
......@@ -492,8 +545,10 @@ static void psmouse_disconnect(struct serio *serio)
static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
{
struct psmouse *psmouse;
struct pm_dev *pmdev;
if ((serio->type & SERIO_TYPE) != SERIO_8042)
if ((serio->type & SERIO_TYPE) != SERIO_8042 &&
(serio->type & SERIO_TYPE) != SERIO_PS_PSTHRU)
return;
if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL)))
......@@ -506,6 +561,7 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
psmouse->state = PSMOUSE_NEW_DEVICE;
psmouse->serio = serio;
psmouse->dev.private = psmouse;
......@@ -522,6 +578,12 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
return;
}
pmdev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, psmouse_pm_callback);
if (pmdev) {
psmouse->dev.pm_dev = pmdev;
pmdev->data = psmouse;
}
sprintf(psmouse->devname, "%s %s %s",
psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name);
sprintf(psmouse->phys, "%s/input0",
......@@ -539,6 +601,10 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys);
psmouse_initialize(psmouse);
synaptics_pt_init(psmouse);
psmouse_activate(psmouse);
}
static struct serio_dev psmouse_dev = {
......@@ -567,9 +633,16 @@ static int __init psmouse_smartscroll_setup(char *str)
return 1;
}
static int __init psmouse_resetafter_setup(char *str)
{
get_option(&str, &psmouse_resetafter);
return 1;
}
__setup("psmouse_noext", psmouse_noext_setup);
__setup("psmouse_resolution=", psmouse_resolution_setup);
__setup("psmouse_smartscroll=", psmouse_smartscroll_setup);
__setup("psmouse_resetafter=", psmouse_resetafter_setup);
#endif
......
......@@ -13,9 +13,15 @@
#define PSMOUSE_CMD_RESET_BAT 0x02ff
#define PSMOUSE_RET_BAT 0xaa
#define PSMOUSE_RET_ID 0x00
#define PSMOUSE_RET_ACK 0xfa
#define PSMOUSE_RET_NAK 0xfe
/* psmouse states */
#define PSMOUSE_NEW_DEVICE 0
#define PSMOUSE_ACTIVATED 1
#define PSMOUSE_IGNORE 2
struct psmouse {
void *private;
struct input_dev dev;
......@@ -29,6 +35,7 @@ struct psmouse {
unsigned char type;
unsigned char model;
unsigned long last;
unsigned char state;
char acking;
volatile char ack;
char error;
......@@ -36,16 +43,17 @@ struct psmouse {
char phys[32];
};
#define PSMOUSE_PS2 1
#define PSMOUSE_PS2PP 2
#define PSMOUSE_PS2TPP 3
#define PSMOUSE_GENPS 4
#define PSMOUSE_IMPS 5
#define PSMOUSE_IMEX 6
#define PSMOUSE_SYNAPTICS 7
#define PSMOUSE_PS2 1
#define PSMOUSE_PS2PP 2
#define PSMOUSE_PS2TPP 3
#define PSMOUSE_GENPS 4
#define PSMOUSE_IMPS 5
#define PSMOUSE_IMEX 6
#define PSMOUSE_SYNAPTICS 7
int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command);
extern int psmouse_smartscroll;
extern unsigned int psmouse_resetafter;
#endif /* _PSMOUSE_H */
/*
* Synaptics TouchPad PS/2 mouse driver
*
* 2003 Dmitry Torokhov <dtor@mail.ru>
* Added support for pass-through port
*
* 2003 Peter Osterlund <petero2@telia.com>
* Ported to 2.5 input device infrastructure.
*
......@@ -21,6 +24,7 @@
#include <linux/module.h>
#include <linux/input.h>
#include <linux/serio.h>
#include "psmouse.h"
#include "synaptics.h"
......@@ -71,7 +75,7 @@ static int synaptics_set_mode(struct psmouse *psmouse, unsigned char mode)
if (synaptics_special_cmd(psmouse, mode))
return -1;
param[0] = 0x14;
param[0] = SYN_PS_SET_MODE2;
if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE))
return -1;
return 0;
......@@ -83,7 +87,7 @@ static int synaptics_reset(struct psmouse *psmouse)
if (psmouse_command(psmouse, r, PSMOUSE_CMD_RESET_BAT))
return -1;
if (r[0] == 0xAA && r[1] == 0x00)
if (r[0] == PSMOUSE_RET_BAT && r[1] == PSMOUSE_RET_ID)
return 0;
return -1;
}
......@@ -106,16 +110,25 @@ static int synaptics_model_id(struct psmouse *psmouse, unsigned long int *model_
* Read the capability-bits from the touchpad
* see also the SYN_CAP_* macros
*/
static int synaptics_capability(struct psmouse *psmouse, unsigned long int *capability)
static int synaptics_capability(struct psmouse *psmouse, unsigned long int *capability, unsigned long int *ext_cap)
{
unsigned char cap[3];
if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap))
return -1;
*capability = (cap[0]<<16) | (cap[1]<<8) | cap[2];
if (SYN_CAP_VALID(*capability))
return 0;
return -1;
*ext_cap = 0;
if (!SYN_CAP_VALID(*capability))
return -1;
if (SYN_EXT_CAP_REQUESTS(*capability)) {
if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) {
printk(KERN_ERR "Synaptics claims to have extended capabilities,"
" but I'm not able to read them.");
} else
*ext_cap = (cap[0]<<16) | (cap[1]<<8) | cap[2];
}
return 0;
}
/*
......@@ -134,19 +147,11 @@ static int synaptics_identify(struct psmouse *psmouse, unsigned long int *ident)
return -1;
}
static int synaptics_enable_device(struct psmouse *psmouse)
{
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE))
return -1;
return 0;
}
static void print_ident(struct synaptics_data *priv)
{
printk(KERN_INFO "Synaptics Touchpad, model: %ld\n", SYN_ID_MODEL(priv->identity));
printk(KERN_INFO " Firware: %ld.%ld\n", SYN_ID_MAJOR(priv->identity),
printk(KERN_INFO " Firmware: %ld.%ld\n", SYN_ID_MAJOR(priv->identity),
SYN_ID_MINOR(priv->identity));
if (SYN_MODEL_ROT180(priv->model_id))
printk(KERN_INFO " 180 degree mounted touchpad\n");
if (SYN_MODEL_PORTRAIT(priv->model_id))
......@@ -159,12 +164,17 @@ static void print_ident(struct synaptics_data *priv)
if (SYN_CAP_EXTENDED(priv->capabilities)) {
printk(KERN_INFO " Touchpad has extended capability bits\n");
if (SYN_CAP_FOUR_BUTTON(priv->capabilities))
if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
printk(KERN_INFO " -> %d multi-buttons, i.e. besides standard buttons\n",
(int)(SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap)));
else if (SYN_CAP_FOUR_BUTTON(priv->capabilities))
printk(KERN_INFO " -> four buttons\n");
if (SYN_CAP_MULTIFINGER(priv->capabilities))
printk(KERN_INFO " -> multifinger detection\n");
if (SYN_CAP_PALMDETECT(priv->capabilities))
printk(KERN_INFO " -> palm detection\n");
if (SYN_CAP_PASS_THROUGH(priv->capabilities))
printk(KERN_INFO " -> pass-through port\n");
}
}
......@@ -172,6 +182,7 @@ static int query_hardware(struct psmouse *psmouse)
{
struct synaptics_data *priv = psmouse->private;
int retries = 0;
int mode;
while ((retries++ < 3) && synaptics_reset(psmouse))
printk(KERN_ERR "synaptics reset failed\n");
......@@ -180,17 +191,107 @@ static int query_hardware(struct psmouse *psmouse)
return -1;
if (synaptics_model_id(psmouse, &priv->model_id))
return -1;
if (synaptics_capability(psmouse, &priv->capabilities))
if (synaptics_capability(psmouse, &priv->capabilities, &priv->ext_cap))
return -1;
if (synaptics_set_mode(psmouse, (SYN_BIT_ABSOLUTE_MODE |
SYN_BIT_HIGH_RATE |
SYN_BIT_DISABLE_GESTURE |
SYN_BIT_W_MODE)))
mode = SYN_BIT_ABSOLUTE_MODE | SYN_BIT_HIGH_RATE;
if (SYN_ID_MAJOR(priv->identity) >= 4)
mode |= SYN_BIT_DISABLE_GESTURE;
if (SYN_CAP_EXTENDED(priv->capabilities))
mode |= SYN_BIT_W_MODE;
if (synaptics_set_mode(psmouse, mode))
return -1;
synaptics_enable_device(psmouse);
return 0;
}
print_ident(priv);
/*****************************************************************************
* Synaptics pass-through PS/2 port support
****************************************************************************/
static int synaptics_pt_open(struct serio *port)
{
return 0;
}
static void synaptics_pt_close(struct serio *port)
{
}
static int synaptics_pt_write(struct serio *port, unsigned char c)
{
struct psmouse *parent = port->driver;
char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */
if (synaptics_special_cmd(parent, c))
return -1;
if (psmouse_command(parent, &rate_param, PSMOUSE_CMD_SETRATE))
return -1;
return 0;
}
static inline int synaptics_is_pt_packet(unsigned char *buf)
{
return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4;
}
static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet)
{
struct psmouse *child = ptport->private;
if (child) {
if (child->state == PSMOUSE_ACTIVATED) {
serio_interrupt(ptport, packet[1], 0, NULL);
serio_interrupt(ptport, packet[4], 0, NULL);
serio_interrupt(ptport, packet[5], 0, NULL);
if (child->type >= PSMOUSE_GENPS)
serio_interrupt(ptport, packet[2], 0, NULL);
} else if (child->state != PSMOUSE_IGNORE) {
serio_interrupt(ptport, packet[1], 0, NULL);
}
}
}
int synaptics_pt_init(struct psmouse *psmouse)
{
struct synaptics_data *priv = psmouse->private;
struct serio *port;
struct psmouse *child;
if (psmouse->type != PSMOUSE_SYNAPTICS)
return -1;
if (!SYN_CAP_EXTENDED(priv->capabilities))
return -1;
if (!SYN_CAP_PASS_THROUGH(priv->capabilities))
return -1;
priv->ptport = port = kmalloc(sizeof(struct serio), GFP_KERNEL);
if (!port) {
printk(KERN_ERR "synaptics: not enough memory to allocate serio port\n");
return -1;
}
memset(port, 0, sizeof(struct serio));
port->type = SERIO_PS_PSTHRU;
port->name = "Synaptics pass-through";
port->phys = "synaptics-pt/serio0";
port->write = synaptics_pt_write;
port->open = synaptics_pt_open;
port->close = synaptics_pt_close;
port->driver = psmouse;
printk(KERN_INFO "serio: %s port at %s\n", port->name, psmouse->phys);
serio_register_slave_port(port);
/* adjust the touchpad to child's choice of protocol */
child = port->private;
if (child && child->type >= PSMOUSE_GENPS) {
if (synaptics_set_mode(psmouse, (SYN_BIT_ABSOLUTE_MODE |
SYN_BIT_HIGH_RATE |
SYN_BIT_DISABLE_GESTURE |
SYN_BIT_FOUR_BYTE_CLIENT |
SYN_BIT_W_MODE)))
printk(KERN_INFO "synaptics: failed to enable 4-byte guest protocol\n");
}
return 0;
}
......@@ -213,22 +314,27 @@ int synaptics_init(struct psmouse *psmouse)
{
struct synaptics_data *priv;
#ifndef CONFIG_MOUSE_PS2_SYNAPTICS
return -1;
#endif
psmouse->private = priv = kmalloc(sizeof(struct synaptics_data), GFP_KERNEL);
if (!priv)
return -1;
memset(priv, 0, sizeof(struct synaptics_data));
priv->inSync = 1;
priv->out_of_sync = 0;
if (query_hardware(psmouse)) {
printk(KERN_ERR "Unable to query/initialize Synaptics hardware.\n");
goto init_fail;
}
print_ident(priv);
/*
* The x/y limits are taken from the Synaptics TouchPad interfacing Guide,
* which says that they should be valid regardless of the actual size of
* the senser.
* the sensor.
*/
set_bit(EV_ABS, psmouse->dev.evbit);
set_abs_params(&psmouse->dev, ABS_X, 1472, 5472, 0, 0);
......@@ -243,7 +349,24 @@ int synaptics_init(struct psmouse *psmouse)
set_bit(BTN_RIGHT, psmouse->dev.keybit);
set_bit(BTN_FORWARD, psmouse->dev.keybit);
set_bit(BTN_BACK, psmouse->dev.keybit);
if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
default:
printk(KERN_ERR "This touchpad reports more than 8 multi-buttons, don't know how to handle.\n");
case 8:
set_bit(BTN_7, psmouse->dev.keybit);
set_bit(BTN_6, psmouse->dev.keybit);
case 6:
set_bit(BTN_5, psmouse->dev.keybit);
set_bit(BTN_4, psmouse->dev.keybit);
case 4:
set_bit(BTN_3, psmouse->dev.keybit);
set_bit(BTN_2, psmouse->dev.keybit);
case 2:
set_bit(BTN_1, psmouse->dev.keybit);
set_bit(BTN_0, psmouse->dev.keybit);
break;
}
clear_bit(EV_REL, psmouse->dev.evbit);
clear_bit(REL_X, psmouse->dev.relbit);
clear_bit(REL_Y, psmouse->dev.relbit);
......@@ -259,42 +382,85 @@ void synaptics_disconnect(struct psmouse *psmouse)
{
struct synaptics_data *priv = psmouse->private;
kfree(priv);
if (psmouse->type == PSMOUSE_SYNAPTICS && priv) {
synaptics_set_mode(psmouse, 0);
if (priv->ptport) {
serio_unregister_slave_port(priv->ptport);
kfree(priv->ptport);
}
kfree(priv);
}
}
/*****************************************************************************
* Functions to interpret the absolute mode packets
****************************************************************************/
static void synaptics_parse_hw_state(struct synaptics_data *priv, struct synaptics_hw_state *hw)
static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw)
{
unsigned char *buf = priv->proto_buf;
hw->x = (((buf[3] & 0x10) << 8) |
((buf[1] & 0x0f) << 8) |
buf[4]);
hw->y = (((buf[3] & 0x20) << 7) |
((buf[1] & 0xf0) << 4) |
buf[5]);
hw->z = buf[2];
hw->w = (((buf[0] & 0x30) >> 2) |
((buf[0] & 0x04) >> 1) |
((buf[3] & 0x04) >> 2));
hw->left = (buf[0] & 0x01) ? 1 : 0;
hw->right = (buf[0] & 0x2) ? 1 : 0;
hw->up = 0;
hw->down = 0;
hw->b0 = 0;
hw->b1 = 0;
hw->b2 = 0;
hw->b3 = 0;
hw->b4 = 0;
hw->b5 = 0;
hw->b6 = 0;
hw->b7 = 0;
if (SYN_MODEL_NEWABS(priv->model_id)) {
hw->x = (((buf[3] & 0x10) << 8) |
((buf[1] & 0x0f) << 8) |
buf[4]);
hw->y = (((buf[3] & 0x20) << 7) |
((buf[1] & 0xf0) << 4) |
buf[5]);
hw->z = buf[2];
hw->w = (((buf[0] & 0x30) >> 2) |
((buf[0] & 0x04) >> 1) |
((buf[3] & 0x04) >> 2));
hw->left = (buf[0] & 0x01) ? 1 : 0;
hw->right = (buf[0] & 0x02) ? 1 : 0;
if (SYN_CAP_EXTENDED(priv->capabilities) &&
(SYN_CAP_FOUR_BUTTON(priv->capabilities))) {
hw->up = ((buf[3] & 0x01)) ? 1 : 0;
if (hw->left)
hw->up = !hw->up;
hw->down = ((buf[3] & 0x02)) ? 1 : 0;
if (hw->right)
hw->down = !hw->down;
}
if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) &&
((buf[3] & 2) ? !hw->right : hw->right)) {
switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
default:
; /* we did comment while initialising... */
case 8:
hw->b7 = ((buf[5] & 0x08)) ? 1 : 0;
hw->b6 = ((buf[4] & 0x08)) ? 1 : 0;
case 6:
hw->b5 = ((buf[5] & 0x04)) ? 1 : 0;
hw->b4 = ((buf[4] & 0x04)) ? 1 : 0;
case 4:
hw->b3 = ((buf[5] & 0x02)) ? 1 : 0;
hw->b2 = ((buf[4] & 0x02)) ? 1 : 0;
case 2:
hw->b1 = ((buf[5] & 0x01)) ? 1 : 0;
hw->b0 = ((buf[4] & 0x01)) ? 1 : 0;
}
}
} else {
hw->x = (((buf[1] & 0x1f) << 8) | buf[2]);
hw->y = (((buf[4] & 0x1f) << 8) | buf[5]);
hw->z = (((buf[0] & 0x30) << 2) | (buf[3] & 0x3F));
hw->w = (((buf[1] & 0x80) >> 4) | ((buf[0] & 0x04) >> 1));
if (SYN_CAP_EXTENDED(priv->capabilities) &&
(SYN_CAP_FOUR_BUTTON(priv->capabilities))) {
hw->up = ((buf[3] & 0x01)) ? 1 : 0;
if (hw->left)
hw->up = !hw->up;
hw->down = ((buf[3] & 0x02)) ? 1 : 0;
if (hw->right)
hw->down = !hw->down;
hw->left = (buf[0] & 0x01) ? 1 : 0;
hw->right = (buf[0] & 0x02) ? 1 : 0;
}
}
......@@ -307,7 +473,7 @@ static void synaptics_process_packet(struct psmouse *psmouse)
struct synaptics_data *priv = psmouse->private;
struct synaptics_hw_state hw;
synaptics_parse_hw_state(priv, &hw);
synaptics_parse_hw_state(psmouse->packet, priv, &hw);
if (hw.z > 0) {
int w_ok = 0;
......@@ -347,7 +513,24 @@ static void synaptics_process_packet(struct psmouse *psmouse)
input_report_key(dev, BTN_RIGHT, hw.right);
input_report_key(dev, BTN_FORWARD, hw.up);
input_report_key(dev, BTN_BACK, hw.down);
if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
switch(SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
default:
; /* we did comment while initialising... */
case 8:
input_report_key(dev, BTN_7, hw.b7);
input_report_key(dev, BTN_6, hw.b6);
case 6:
input_report_key(dev, BTN_5, hw.b5);
input_report_key(dev, BTN_4, hw.b4);
case 4:
input_report_key(dev, BTN_3, hw.b3);
input_report_key(dev, BTN_2, hw.b2);
case 2:
input_report_key(dev, BTN_1, hw.b1);
input_report_key(dev, BTN_0, hw.b0);
break;
}
input_sync(dev);
}
......@@ -355,35 +538,59 @@ void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
{
struct input_dev *dev = &psmouse->dev;
struct synaptics_data *priv = psmouse->private;
unsigned char *pBuf = priv->proto_buf;
unsigned char u = psmouse->packet[0];
unsigned char data = psmouse->packet[psmouse->pktcnt - 1];
int newabs = SYN_MODEL_NEWABS(priv->model_id);
input_regs(dev, regs);
pBuf[priv->proto_buf_tail++] = u;
/* check first byte */
if ((priv->proto_buf_tail == 1) && ((u & 0xC8) != 0x80)) {
priv->inSync = 0;
priv->proto_buf_tail = 0;
printk(KERN_WARNING "Synaptics driver lost sync at 1st byte\n");
return;
}
switch (psmouse->pktcnt) {
case 1:
if (newabs ? ((data & 0xC8) != 0x80) : ((data & 0xC0) != 0xC0)) {
printk(KERN_WARNING "Synaptics driver lost sync at 1st byte\n");
goto bad_sync;
}
break;
case 2:
if (!newabs && ((data & 0x60) != 0x00)) {
printk(KERN_WARNING "Synaptics driver lost sync at 2nd byte\n");
goto bad_sync;
}
break;
case 4:
if (newabs ? ((data & 0xC8) != 0xC0) : ((data & 0xC0) != 0x80)) {
printk(KERN_WARNING "Synaptics driver lost sync at 4th byte\n");
goto bad_sync;
}
break;
case 5:
if (!newabs && ((data & 0x60) != 0x00)) {
printk(KERN_WARNING "Synaptics driver lost sync at 5th byte\n");
goto bad_sync;
}
break;
default:
if (psmouse->pktcnt >= 6) { /* Full packet received */
if (priv->out_of_sync) {
priv->out_of_sync = 0;
printk(KERN_NOTICE "Synaptics driver resynced.\n");
}
/* check 4th byte */
if ((priv->proto_buf_tail == 4) && ((u & 0xc8) != 0xc0)) {
priv->inSync = 0;
priv->proto_buf_tail = 0;
printk(KERN_WARNING "Synaptics driver lost sync at 4th byte\n");
return;
}
if (priv->ptport && synaptics_is_pt_packet(psmouse->packet))
synaptics_pass_pt_packet(priv->ptport, psmouse->packet);
else
synaptics_process_packet(psmouse);
if (priv->proto_buf_tail >= 6) { /* Full packet received */
if (!priv->inSync) {
priv->inSync = 1;
printk(KERN_NOTICE "Synaptics driver resynced.\n");
psmouse->pktcnt = 0;
}
synaptics_process_packet(psmouse);
priv->proto_buf_tail = 0;
break;
}
return;
bad_sync:
priv->out_of_sync++;
psmouse->pktcnt = 0;
if (psmouse_resetafter > 0 && priv->out_of_sync == psmouse_resetafter) {
psmouse->state = PSMOUSE_IGNORE;
serio_rescan(psmouse->serio);
}
}
......@@ -12,6 +12,7 @@
extern void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs);
extern int synaptics_init(struct psmouse *psmouse);
extern int synaptics_pt_init(struct psmouse *psmouse);
extern void synaptics_disconnect(struct psmouse *psmouse);
/* synaptics queries */
......@@ -22,12 +23,14 @@ extern void synaptics_disconnect(struct psmouse *psmouse);
#define SYN_QUE_SERIAL_NUMBER_PREFIX 0x06
#define SYN_QUE_SERIAL_NUMBER_SUFFIX 0x07
#define SYN_QUE_RESOLUTION 0x08
#define SYN_QUE_EXT_CAPAB 0x09
/* synatics modes */
#define SYN_BIT_ABSOLUTE_MODE (1 << 7)
#define SYN_BIT_HIGH_RATE (1 << 6)
#define SYN_BIT_SLEEP_MODE (1 << 3)
#define SYN_BIT_DISABLE_GESTURE (1 << 2)
#define SYN_BIT_FOUR_BYTE_CLIENT (1 << 1)
#define SYN_BIT_W_MODE (1 << 0)
/* synaptics model ID bits */
......@@ -42,11 +45,14 @@ extern void synaptics_disconnect(struct psmouse *psmouse);
/* synaptics capability bits */
#define SYN_CAP_EXTENDED(c) ((c) & (1 << 23))
#define SYN_CAP_PASS_THROUGH(c) ((c) & (1 << 7))
#define SYN_CAP_SLEEP(c) ((c) & (1 << 4))
#define SYN_CAP_FOUR_BUTTON(c) ((c) & (1 << 3))
#define SYN_CAP_MULTIFINGER(c) ((c) & (1 << 1))
#define SYN_CAP_PALMDETECT(c) ((c) & (1 << 0))
#define SYN_CAP_VALID(c) ((((c) & 0x00ff00) >> 8) == 0x47)
#define SYN_EXT_CAP_REQUESTS(c) ((((c) & 0x700000) >> 20) == 1)
#define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12)
/* synaptics modes query bits */
#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7))
......@@ -62,6 +68,10 @@ extern void synaptics_disconnect(struct psmouse *psmouse);
#define SYN_ID_MINOR(i) (((i) >> 16) & 0xff)
#define SYN_ID_IS_SYNAPTICS(i) ((((i) >> 8) & 0xff) == 0x47)
/* synaptics special commands */
#define SYN_PS_SET_MODE2 0x14
#define SYN_PS_CLIENT_CMD 0x28
/*
* A structure to describe the state of the touchpad hardware (buttons and pad)
*/
......@@ -75,21 +85,28 @@ struct synaptics_hw_state {
int right;
int up;
int down;
int b0;
int b1;
int b2;
int b3;
int b4;
int b5;
int b6;
int b7;
};
struct synaptics_data {
/* Data read from the touchpad */
unsigned long int model_id; /* Model-ID */
unsigned long int capabilities; /* Capabilities */
unsigned long int ext_cap; /* Extended Capabilities */
unsigned long int identity; /* Identification */
/* Data for normal processing */
unsigned char proto_buf[6]; /* Buffer for Packet */
unsigned char last_byte; /* last received byte */
int inSync; /* Packets in sync */
int proto_buf_tail;
unsigned int out_of_sync; /* # of packets out of sync */
int old_w; /* Previous w value */
struct serio *ptport; /* pass-through port */
};
#endif /* _SYNAPTICS_H */
......@@ -49,7 +49,9 @@ MODULE_LICENSE("GPL");
EXPORT_SYMBOL(serio_interrupt);
EXPORT_SYMBOL(serio_register_port);
EXPORT_SYMBOL(serio_register_slave_port);
EXPORT_SYMBOL(serio_unregister_port);
EXPORT_SYMBOL(serio_unregister_slave_port);
EXPORT_SYMBOL(serio_register_device);
EXPORT_SYMBOL(serio_unregister_device);
EXPORT_SYMBOL(serio_open);
......@@ -166,6 +168,17 @@ void serio_register_port(struct serio *serio)
up(&serio_sem);
}
/*
* Same as serio_register_port but does not try to acquire serio_sem.
* Should be used when registering a serio from other input device's
* connect() function.
*/
void serio_register_slave_port(struct serio *serio)
{
list_add_tail(&serio->node, &serio_list);
serio_find_dev(serio);
}
void serio_unregister_port(struct serio *serio)
{
down(&serio_sem);
......@@ -175,6 +188,18 @@ void serio_unregister_port(struct serio *serio)
up(&serio_sem);
}
/*
* Same as serio_unregister_port but does not try to acquire serio_sem.
* Should be used when unregistering a serio from other input device's
* disconnect() function.
*/
void serio_unregister_slave_port(struct serio *serio)
{
list_del_init(&serio->node);
if (serio->dev && serio->dev->disconnect)
serio->dev->disconnect(serio);
}
void serio_register_device(struct serio_dev *dev)
{
struct serio *serio;
......@@ -204,9 +229,11 @@ void serio_unregister_device(struct serio_dev *dev)
/* called from serio_dev->connect/disconnect methods under serio_sem */
int serio_open(struct serio *serio, struct serio_dev *dev)
{
if (serio->open(serio))
return -1;
serio->dev = dev;
if (serio->open(serio)) {
serio->dev = NULL;
return -1;
}
return 0;
}
......
......@@ -751,7 +751,7 @@ struct ff_effect {
#define LONG(x) ((x)/BITS_PER_LONG)
#define INPUT_KEYCODE(dev, scancode) ((dev->keycodesize == 1) ? ((u8*)dev->keycode)[scancode] : \
((dev->keycodesize == 1) ? ((u16*)dev->keycode)[scancode] : (((u32*)dev->keycode)[scancode])))
((dev->keycodesize == 2) ? ((u16*)dev->keycode)[scancode] : (((u32*)dev->keycode)[scancode])))
#define init_input_dev(dev) do { INIT_LIST_HEAD(&((dev)->h_list)); INIT_LIST_HEAD(&((dev)->node)); } while (0)
......
......@@ -65,7 +65,9 @@ void serio_rescan(struct serio *serio);
irqreturn_t serio_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs);
void serio_register_port(struct serio *serio);
void serio_register_slave_port(struct serio *serio);
void serio_unregister_port(struct serio *serio);
void serio_unregister_slave_port(struct serio *serio);
void serio_register_device(struct serio_dev *dev);
void serio_unregister_device(struct serio_dev *dev);
......@@ -104,6 +106,7 @@ static __inline__ void serio_cleanup(struct serio *serio)
#define SERIO_RS232 0x02000000UL
#define SERIO_HIL_MLC 0x03000000UL
#define SERIO_PC9800 0x04000000UL
#define SERIO_PS_PSTHRU 0x05000000UL
#define SERIO_PROTO 0xFFUL
#define SERIO_MSC 0x01
......
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