Commit 1e12aaf0 authored by Vojtech Pavlik's avatar Vojtech Pavlik

Merge suse.cz:/home/vojtech/bk/linus

into suse.cz:/home/vojtech/bk/for-linus
parents 7b0f9236 56b3ffec
...@@ -896,8 +896,8 @@ running once the system is up. ...@@ -896,8 +896,8 @@ running once the system is up.
psmouse.rate= [HW,MOUSE] Set desired mouse report rate, in reports psmouse.rate= [HW,MOUSE] Set desired mouse report rate, in reports
per second. per second.
psmouse.resetafter= psmouse.resetafter=
[HW,MOUSE] Try to reset Synaptics Touchpad after so many [HW,MOUSE] Try to reset the device after so many bad packets
bad packets (0 = never). (0 = never).
psmouse.resolution= psmouse.resolution=
[HW,MOUSE] Set desired mouse resolution, in dpi. [HW,MOUSE] Set desired mouse resolution, in dpi.
psmouse.smartscroll= psmouse.smartscroll=
......
...@@ -41,9 +41,16 @@ config INPUT_MOUSEDEV ...@@ -41,9 +41,16 @@ config INPUT_MOUSEDEV
module will be called mousedev. module will be called mousedev.
config INPUT_MOUSEDEV_PSAUX config INPUT_MOUSEDEV_PSAUX
bool "Provide legacy /dev/psaux device" if EMBEDDED bool "Provide legacy /dev/psaux device"
default y default y
depends on INPUT_MOUSEDEV depends on INPUT_MOUSEDEV
---help---
Say Y here if you want your mouse also be accessible as char device
10:1 - /dev/psaux. The data available through /dev/psaux is exactly
the same as the data from /dev/input/mice.
If unsure, say Y.
config INPUT_MOUSEDEV_SCREEN_X config INPUT_MOUSEDEV_SCREEN_X
int "Horizontal screen resolution" int "Horizontal screen resolution"
......
...@@ -126,7 +126,7 @@ static int evdev_open(struct inode * inode, struct file * file) ...@@ -126,7 +126,7 @@ static int evdev_open(struct inode * inode, struct file * file)
int i = iminor(inode) - EVDEV_MINOR_BASE; int i = iminor(inode) - EVDEV_MINOR_BASE;
int accept_err; int accept_err;
if (i >= EVDEV_MINORS || !evdev_table[i]) if (i >= EVDEV_MINORS || !evdev_table[i] || !evdev_table[i]->exist)
return -ENODEV; return -ENODEV;
if ((accept_err = input_accept_process(&(evdev_table[i]->handle), file))) if ((accept_err = input_accept_process(&(evdev_table[i]->handle), file)))
...@@ -175,7 +175,7 @@ static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count ...@@ -175,7 +175,7 @@ static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count
return -EAGAIN; return -EAGAIN;
retval = wait_event_interruptible(list->evdev->wait, retval = wait_event_interruptible(list->evdev->wait,
list->head != list->tail && list->evdev->exist); list->head != list->tail || (!list->evdev->exist));
if (retval) if (retval)
return retval; return retval;
......
...@@ -58,6 +58,9 @@ ...@@ -58,6 +58,9 @@
#include <linux/serio.h> #include <linux/serio.h>
#include <linux/init.h> #include <linux/init.h>
MODULE_DESCRIPTION("Handykey Twiddler keyboard as a joystick driver");
MODULE_LICENSE("GPL");
/* /*
* Constants. * Constants.
*/ */
...@@ -142,7 +145,7 @@ static void twidjoy_process_packet(struct twidjoy *twidjoy, struct pt_regs *regs ...@@ -142,7 +145,7 @@ static void twidjoy_process_packet(struct twidjoy *twidjoy, struct pt_regs *regs
* packet processing routine. * packet processing routine.
*/ */
static void twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struc pt_regs *regs) static irqreturn_t twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs)
{ {
struct twidjoy *twidjoy = serio->private; struct twidjoy *twidjoy = serio->private;
...@@ -153,7 +156,7 @@ static void twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned ...@@ -153,7 +156,7 @@ static void twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned
if ((data & 0x80) == 0) if ((data & 0x80) == 0)
twidjoy->idx = 0; /* this byte starts a new packet */ twidjoy->idx = 0; /* this byte starts a new packet */
else if (twidjoy->idx == 0) else if (twidjoy->idx == 0)
return; /* wrong MSB -- ignore this byte */ return IRQ_HANDLED; /* wrong MSB -- ignore this byte */
if (twidjoy->idx < TWIDJOY_MAX_LENGTH) if (twidjoy->idx < TWIDJOY_MAX_LENGTH)
twidjoy->data[twidjoy->idx++] = data; twidjoy->data[twidjoy->idx++] = data;
...@@ -163,7 +166,7 @@ static void twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned ...@@ -163,7 +166,7 @@ static void twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned
twidjoy->idx = 0; twidjoy->idx = 0;
} }
return; return IRQ_HANDLED;
} }
/* /*
......
...@@ -109,7 +109,7 @@ struct kbd98 { ...@@ -109,7 +109,7 @@ struct kbd98 {
struct jis_kbd_conv jis[16]; struct jis_kbd_conv jis[16];
}; };
void kbd98_interrupt(struct serio *serio, unsigned char data, irqreturn_t kbd98_interrupt(struct serio *serio, unsigned char data,
unsigned int flags, struct pt_regs *regs) unsigned int flags, struct pt_regs *regs)
{ {
struct kbd98 *kbd98 = serio->private; struct kbd98 *kbd98 = serio->private;
...@@ -119,15 +119,15 @@ void kbd98_interrupt(struct serio *serio, unsigned char data, ...@@ -119,15 +119,15 @@ void kbd98_interrupt(struct serio *serio, unsigned char data,
switch (data) { switch (data) {
case KBD98_RET_ACK: case KBD98_RET_ACK:
kbd98->ack = 1; kbd98->ack = 1;
return; goto out;
case KBD98_RET_NAK: case KBD98_RET_NAK:
kbd98->ack = -1; kbd98->ack = -1;
return; goto out;
} }
if (kbd98->cmdcnt) { if (kbd98->cmdcnt) {
kbd98->cmdbuf[--kbd98->cmdcnt] = data; kbd98->cmdbuf[--kbd98->cmdcnt] = data;
return; goto out;
} }
scancode = data & KBD98_KEY; scancode = data & KBD98_KEY;
...@@ -164,7 +164,7 @@ void kbd98_interrupt(struct serio *serio, unsigned char data, ...@@ -164,7 +164,7 @@ void kbd98_interrupt(struct serio *serio, unsigned char data,
keycode = kbd98->jis[i].emul[kbd98->shift].keycode; keycode = kbd98->jis[i].emul[kbd98->shift].keycode;
if (keycode == KBD98_KEY_NULL) if (keycode == KBD98_KEY_NULL)
return; break;
if (press) { if (press) {
kbd98->emul.scancode = scancode; kbd98->emul.scancode = scancode;
...@@ -187,27 +187,31 @@ void kbd98_interrupt(struct serio *serio, unsigned char data, ...@@ -187,27 +187,31 @@ void kbd98_interrupt(struct serio *serio, unsigned char data,
} }
input_sync(&kbd98->dev); input_sync(&kbd98->dev);
return; break;
case KEY_CAPSLOCK: case KEY_CAPSLOCK:
input_report_key(&kbd98->dev, keycode, 1); input_report_key(&kbd98->dev, keycode, 1);
input_sync(&kbd98->dev); input_sync(&kbd98->dev);
input_report_key(&kbd98->dev, keycode, 0); input_report_key(&kbd98->dev, keycode, 0);
input_sync(&kbd98->dev); input_sync(&kbd98->dev);
return; break;
case KBD98_KEY_NULL: case KBD98_KEY_NULL:
return; break;
case 0: case 0:
printk(KERN_WARNING "kbd98.c: Unknown key (scancode %#x) %s.\n", printk(KERN_WARNING "kbd98.c: Unknown key (scancode %#x) %s.\n",
data & KBD98_KEY, data & KBD98_RELEASE ? "released" : "pressed"); data & KBD98_KEY, data & KBD98_RELEASE ? "released" : "pressed");
return; break;
default: default:
input_report_key(&kbd98->dev, keycode, press); input_report_key(&kbd98->dev, keycode, press);
input_sync(&kbd98->dev); input_sync(&kbd98->dev);
break;
} }
out:
return IRQ_HANDLED;
} }
/* /*
......
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/serio.h> #include <linux/serio.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/timer.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("AT and PS/2 keyboard driver"); MODULE_DESCRIPTION("AT and PS/2 keyboard driver");
...@@ -173,22 +172,24 @@ struct atkbd { ...@@ -173,22 +172,24 @@ struct atkbd {
unsigned char keycode[512]; unsigned char keycode[512];
struct input_dev dev; struct input_dev dev;
struct serio *serio; struct serio *serio;
struct timer_list timer;
char name[64]; char name[64];
char phys[32]; char phys[32];
unsigned short id;
unsigned char set;
unsigned int translated:1;
unsigned int extra:1;
unsigned int write:1;
unsigned char cmdbuf[4]; unsigned char cmdbuf[4];
unsigned char cmdcnt; unsigned char cmdcnt;
unsigned char set;
unsigned char extra;
unsigned char release;
int lastkey;
volatile signed char ack; volatile signed char ack;
unsigned char emul; unsigned char emul;
unsigned short id; unsigned int resend:1;
unsigned char write; unsigned int release:1;
unsigned char translated; unsigned int bat_xl:1;
unsigned char resend; unsigned int enabled:1;
unsigned char bat_xl;
unsigned int last; unsigned int last;
unsigned long time; unsigned long time;
}; };
...@@ -248,6 +249,9 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, ...@@ -248,6 +249,9 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
goto out; goto out;
} }
if (!atkbd->enabled)
goto out;
if (atkbd->translated) { if (atkbd->translated) {
if (atkbd->emul || if (atkbd->emul ||
...@@ -300,15 +304,20 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, ...@@ -300,15 +304,20 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
case ATKBD_KEY_NULL: case ATKBD_KEY_NULL:
break; break;
case ATKBD_KEY_UNKNOWN: case ATKBD_KEY_UNKNOWN:
printk(KERN_WARNING "atkbd.c: Unknown key %s (%s set %d, code %#x on %s).\n", if (data == ATKBD_RET_ACK || data == ATKBD_RET_NAK) {
printk(KERN_WARNING "atkbd.c: Spurious %s on %s. Some program, "
"like XFree86, might be trying access hardware directly.\n",
data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
} else {
printk(KERN_WARNING "atkbd.c: Unknown key %s "
"(%s set %d, code %#x on %s).\n",
atkbd->release ? "released" : "pressed", atkbd->release ? "released" : "pressed",
atkbd->translated ? "translated" : "raw", atkbd->translated ? "translated" : "raw",
atkbd->set, code, serio->phys); atkbd->set, code, serio->phys);
if (atkbd->translated && atkbd->set == 2 && code == 0x7a) printk(KERN_WARNING "atkbd.c: Use 'setkeycodes %s%02x <keycode>' "
printk(KERN_WARNING "atkbd.c: This is an XFree86 bug. It shouldn't access" "to make it known.\n",
" hardware directly.\n"); code & 0x80 ? "e0" : "", code & 0x7f);
else }
printk(KERN_WARNING "atkbd.c: Use 'setkeycodes %s%02x <keycode>' to make it known.\n", code & 0x80 ? "e0" : "", code & 0x7f);
break; break;
case ATKBD_SCR_1: case ATKBD_SCR_1:
scroll = 1 - atkbd->release * 2; scroll = 1 - atkbd->release * 2;
...@@ -745,6 +754,8 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) ...@@ -745,6 +754,8 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
atkbd->id = 0xab00; atkbd->id = 0xab00;
} }
atkbd->enabled = 1;
if (atkbd->extra) { if (atkbd->extra) {
atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | BIT(LED_SLEEP) | BIT(LED_MUTE) | BIT(LED_MISC); atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | BIT(LED_SLEEP) | BIT(LED_MUTE) | BIT(LED_MISC);
sprintf(atkbd->name, "AT Set 2 Extra keyboard"); sprintf(atkbd->name, "AT Set 2 Extra keyboard");
......
...@@ -14,6 +14,25 @@ ...@@ -14,6 +14,25 @@
#include "psmouse.h" #include "psmouse.h"
#include "logips2pp.h" #include "logips2pp.h"
/* Logitech mouse types */
#define PS2PP_KIND_WHEEL 1
#define PS2PP_KIND_MX 2
#define PS2PP_KIND_TP3 3
/* Logitech mouse features */
#define PS2PP_WHEEL 0x01
#define PS2PP_HWHEEL 0x02
#define PS2PP_SIDE_BTN 0x04
#define PS2PP_EXTRA_BTN 0x08
#define PS2PP_TASK_BTN 0x10
#define PS2PP_NAV_BTN 0x20
struct ps2pp_info {
const int model;
unsigned const int kind;
unsigned const int features;
};
/* /*
* Process a PS2++ or PS2T++ packet. * Process a PS2++ or PS2T++ packet.
*/ */
...@@ -63,7 +82,6 @@ void ps2pp_process_packet(struct psmouse *psmouse) ...@@ -63,7 +82,6 @@ void ps2pp_process_packet(struct psmouse *psmouse)
packet[0] &= 0x0f; packet[0] &= 0x0f;
packet[1] = 0; packet[1] = 0;
packet[2] = 0; packet[2] = 0;
} }
} }
...@@ -76,18 +94,9 @@ void ps2pp_process_packet(struct psmouse *psmouse) ...@@ -76,18 +94,9 @@ void ps2pp_process_packet(struct psmouse *psmouse)
static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned char command) static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned char command)
{ {
unsigned char d; if (psmouse_sliced_command(psmouse, command))
int i;
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11))
return -1; return -1;
for (i = 6; i >= 0; i -= 2) {
d = (command >> i) & 3;
if(psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES))
return -1;
}
if (psmouse_command(psmouse, param, PSMOUSE_CMD_POLL)) if (psmouse_command(psmouse, param, PSMOUSE_CMD_POLL))
return -1; return -1;
...@@ -113,14 +122,11 @@ static void ps2pp_set_smartscroll(struct psmouse *psmouse) ...@@ -113,14 +122,11 @@ static void ps2pp_set_smartscroll(struct psmouse *psmouse)
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
if (psmouse_smartscroll == 1) if (psmouse_smartscroll < 2) {
param[0] = 1; /* 0 - disabled, 1 - enabled */
else param[0] = psmouse_smartscroll;
if (psmouse_smartscroll > 2)
return;
/* else leave param[0] == 0 to disable */
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
}
} }
/* /*
...@@ -138,133 +144,167 @@ void ps2pp_set_800dpi(struct psmouse *psmouse) ...@@ -138,133 +144,167 @@ void ps2pp_set_800dpi(struct psmouse *psmouse)
psmouse_command(psmouse, &param, PSMOUSE_CMD_SETRES); psmouse_command(psmouse, &param, PSMOUSE_CMD_SETRES);
} }
/* static struct ps2pp_info *get_model_info(unsigned char model)
* Detect the exact model and features of a PS2++ or PS2T++ Logitech mouse or
* touchpad.
*/
static int ps2pp_detect_model(struct psmouse *psmouse, unsigned char *param)
{ {
int i; static struct ps2pp_info ps2pp_list[] = {
static struct _logips2_list { { 12, 0, PS2PP_SIDE_BTN},
const int model; { 13, 0, 0 },
unsigned const int features; { 40, 0, PS2PP_SIDE_BTN },
} logips2pp_list [] = { { 41, 0, PS2PP_SIDE_BTN },
{ 12, PS2PP_4BTN}, { 42, 0, PS2PP_SIDE_BTN },
{ 13, 0 }, { 43, 0, PS2PP_SIDE_BTN },
{ 40, PS2PP_4BTN }, { 50, 0, 0 },
{ 41, PS2PP_4BTN }, { 51, 0, 0 },
{ 42, PS2PP_4BTN }, { 52, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL },
{ 43, PS2PP_4BTN }, { 53, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
{ 50, 0 }, { 61, PS2PP_KIND_MX,
{ 51, 0 }, PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
{ 52, PS2PP_4BTN | PS2PP_WHEEL }, PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, /* MX700 */
{ 53, PS2PP_WHEEL }, { 73, 0, PS2PP_SIDE_BTN },
{ 61, PS2PP_WHEEL | PS2PP_MX }, /* MX700 */ { 75, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
{ 73, PS2PP_4BTN }, { 76, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
{ 75, PS2PP_WHEEL }, { 80, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL },
{ 76, PS2PP_WHEEL }, { 81, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
{ 80, PS2PP_4BTN | PS2PP_WHEEL }, { 83, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
{ 81, PS2PP_WHEEL }, { 88, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
{ 83, PS2PP_WHEEL }, { 96, 0, 0 },
{ 88, PS2PP_WHEEL }, { 97, PS2PP_KIND_TP3, PS2PP_WHEEL | PS2PP_HWHEEL },
{ 96, 0 }, { 100, PS2PP_KIND_MX,
{ 97, 0 }, PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
{ 100 , PS2PP_WHEEL | PS2PP_MX }, /* MX510 */ PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, /* MX510 */
{ 112 , PS2PP_WHEEL | PS2PP_MX }, /* MX500 */ { 112, PS2PP_KIND_MX,
{ 114 , PS2PP_WHEEL | PS2PP_MX | PS2PP_MX310 }, /* MX310 */ PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, /* MX500 */
{ 114, PS2PP_KIND_MX,
PS2PP_WHEEL | PS2PP_SIDE_BTN |
PS2PP_TASK_BTN | PS2PP_EXTRA_BTN }, /* M310 */
{ } { }
}; };
int i;
psmouse->vendor = "Logitech"; for (i = 0; ps2pp_list[i].model; i++)
psmouse->model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78); if (model == ps2pp_list[i].model)
return &ps2pp_list[i];
if (param[1] < 3) return NULL;
clear_bit(BTN_MIDDLE, psmouse->dev.keybit); }
if (param[1] < 2)
clear_bit(BTN_RIGHT, psmouse->dev.keybit);
psmouse->type = PSMOUSE_PS2; /*
* Set up input device's properties based on the detected mouse model.
*/
for (i = 0; logips2pp_list[i].model; i++){ static void ps2pp_set_model_properties(struct psmouse *psmouse, struct ps2pp_info *model_info)
if (logips2pp_list[i].model == psmouse->model){ {
psmouse->type = PSMOUSE_PS2PP; if (model_info->features & PS2PP_SIDE_BTN)
if (logips2pp_list[i].features & PS2PP_4BTN)
set_bit(BTN_SIDE, psmouse->dev.keybit); set_bit(BTN_SIDE, psmouse->dev.keybit);
if (logips2pp_list[i].features & PS2PP_WHEEL){ if (model_info->features & PS2PP_EXTRA_BTN)
set_bit(REL_WHEEL, psmouse->dev.relbit);
psmouse->name = "Wheel Mouse";
}
if (logips2pp_list[i].features & PS2PP_MX) {
set_bit(BTN_SIDE, psmouse->dev.keybit);
set_bit(BTN_EXTRA, psmouse->dev.keybit); set_bit(BTN_EXTRA, psmouse->dev.keybit);
if (model_info->features & PS2PP_TASK_BTN)
set_bit(BTN_TASK, psmouse->dev.keybit); set_bit(BTN_TASK, psmouse->dev.keybit);
if (!(logips2pp_list[i].features & PS2PP_MX310)){
set_bit(BTN_BACK, psmouse->dev.keybit); if (model_info->features & PS2PP_NAV_BTN) {
set_bit(BTN_FORWARD, psmouse->dev.keybit); set_bit(BTN_FORWARD, psmouse->dev.keybit);
set_bit(BTN_BACK, psmouse->dev.keybit);
} }
if (model_info->features & PS2PP_WHEEL)
set_bit(REL_WHEEL, psmouse->dev.relbit);
if (model_info->features & PS2PP_HWHEEL)
set_bit(REL_HWHEEL, psmouse->dev.relbit);
switch (model_info->kind) {
case PS2PP_KIND_WHEEL:
psmouse->name = "Wheel Mouse";
break;
case PS2PP_KIND_MX:
psmouse->name = "MX Mouse"; psmouse->name = "MX Mouse";
} break;
case PS2PP_KIND_TP3:
psmouse->name = "TouchPad 3";
break; break;
} }
} }
/* /*
* Do Logitech PS2++ / PS2T++ magic init. * Logitech magic init. Detect whether the mouse is a Logitech one
* and its exact model and try turning on extended protocol for ones
* that support it.
*/ */
if (psmouse->type == PSMOUSE_PS2PP) {
if (psmouse->model == 97) { /* TouchPad 3 */ int ps2pp_init(struct psmouse *psmouse, int set_properties)
{
unsigned char param[4];
unsigned char protocol = PSMOUSE_PS2;
unsigned char model, buttons;
struct ps2pp_info *model_info;
set_bit(REL_WHEEL, psmouse->dev.relbit); param[0] = 0;
set_bit(REL_HWHEEL, psmouse->dev.relbit); psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
param[1] = 0;
psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
if (param[1] != 0) {
model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78);
buttons = param[1];
model_info = get_model_info(model);
param[0] = 0x11; param[1] = 0x04; param[2] = 0x68; /* Unprotect RAM */ /*
* Do Logitech PS2++ / PS2T++ magic init.
*/
if (model == 97) { /* Touch Pad 3 */
/* Unprotect RAM */
param[0] = 0x11; param[1] = 0x04; param[2] = 0x68;
psmouse_command(psmouse, param, 0x30d1); psmouse_command(psmouse, param, 0x30d1);
param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b; /* Enable features */ /* Enable features */
param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b;
psmouse_command(psmouse, param, 0x30d1); psmouse_command(psmouse, param, 0x30d1);
param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3; /* Enable PS2++ */ /* Enable PS2++ */
param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3;
psmouse_command(psmouse, param, 0x30d1); psmouse_command(psmouse, param, 0x30d1);
param[0] = 0; param[0] = 0;
if (!psmouse_command(psmouse, param, 0x13d1) && if (!psmouse_command(psmouse, param, 0x13d1) &&
param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) { param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) {
psmouse->name = "TouchPad 3"; protocol = PSMOUSE_PS2TPP;
return PSMOUSE_PS2TPP;
} }
} else { } else if (get_model_info(model) != 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 */
ps2pp_cmd(psmouse, param, 0xDB); ps2pp_cmd(psmouse, param, 0xDB);
if ((param[0] & 0x78) == 0x48 && (param[1] & 0xf3) == 0xc2 && if ((param[0] & 0x78) == 0x48 &&
(param[2] & 3) == ((param[1] >> 2) & 3)) { (param[1] & 0xf3) == 0xc2 &&
(param[2] & 0x03) == ((param[1] >> 2) & 3)) {
ps2pp_set_smartscroll(psmouse); ps2pp_set_smartscroll(psmouse);
return PSMOUSE_PS2PP; protocol = PSMOUSE_PS2PP;
}
} }
} }
return 0; if (set_properties) {
} psmouse->vendor = "Logitech";
psmouse->model = model;
/* if (buttons < 3)
* Logitech magic init. clear_bit(BTN_MIDDLE, psmouse->dev.keybit);
*/ if (buttons < 2)
int ps2pp_detect(struct psmouse *psmouse) clear_bit(BTN_RIGHT, psmouse->dev.keybit);
{
unsigned char param[4];
param[0] = 0; if (model_info)
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); ps2pp_set_model_properties(psmouse, model_info);
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); }
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); }
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
param[1] = 0;
psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
return param[1] != 0 ? ps2pp_detect_model(psmouse, param) : 0; return protocol;
} }
...@@ -11,13 +11,8 @@ ...@@ -11,13 +11,8 @@
#ifndef _LOGIPS2PP_H #ifndef _LOGIPS2PP_H
#define _LOGIPS2PP_H #define _LOGIPS2PP_H
#define PS2PP_4BTN 0x01
#define PS2PP_WHEEL 0x02
#define PS2PP_MX 0x04
#define PS2PP_MX310 0x08
struct psmouse;
void ps2pp_process_packet(struct psmouse *psmouse); void ps2pp_process_packet(struct psmouse *psmouse);
void ps2pp_set_800dpi(struct psmouse *psmouse); void ps2pp_set_800dpi(struct psmouse *psmouse);
int ps2pp_detect(struct psmouse *psmouse); int ps2pp_init(struct psmouse *psmouse, int set_properties);
#endif #endif
...@@ -43,9 +43,9 @@ int psmouse_smartscroll = 1; ...@@ -43,9 +43,9 @@ int psmouse_smartscroll = 1;
module_param_named(smartscroll, psmouse_smartscroll, bool, 0); module_param_named(smartscroll, psmouse_smartscroll, bool, 0);
MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled."); MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled.");
unsigned int psmouse_resetafter; static unsigned int psmouse_resetafter;
module_param_named(resetafter, psmouse_resetafter, uint, 0); module_param_named(resetafter, psmouse_resetafter, uint, 0);
MODULE_PARM_DESC(resetafter, "Reset Synaptics Touchpad after so many bad packets (0 = never)."); MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never).");
__obsolete_setup("psmouse_noext"); __obsolete_setup("psmouse_noext");
__obsolete_setup("psmouse_resolution="); __obsolete_setup("psmouse_resolution=");
...@@ -56,15 +56,22 @@ __obsolete_setup("psmouse_rate="); ...@@ -56,15 +56,22 @@ __obsolete_setup("psmouse_rate=");
static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2"}; static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2"};
/* /*
* psmouse_process_packet() analyzes the PS/2 mouse packet contents and * psmouse_process_byte() analyzes the PS/2 data stream and reports
* reports relevant events to the input module. * relevant events to the input module once full packet has arrived.
*/ */
static void psmouse_process_packet(struct psmouse *psmouse, struct pt_regs *regs) static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
{ {
struct input_dev *dev = &psmouse->dev; struct input_dev *dev = &psmouse->dev;
unsigned char *packet = psmouse->packet; unsigned char *packet = psmouse->packet;
if (psmouse->pktcnt < 3 + (psmouse->type >= PSMOUSE_GENPS))
return PSMOUSE_GOOD_DATA;
/*
* Full packet accumulated, process it
*/
input_regs(dev, regs); input_regs(dev, regs);
/* /*
...@@ -112,6 +119,8 @@ static void psmouse_process_packet(struct psmouse *psmouse, struct pt_regs *regs ...@@ -112,6 +119,8 @@ static void psmouse_process_packet(struct psmouse *psmouse, struct pt_regs *regs
input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0); input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0);
input_sync(dev); input_sync(dev);
return PSMOUSE_FULL_PACKET;
} }
/* /*
...@@ -123,6 +132,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, ...@@ -123,6 +132,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
unsigned char data, unsigned int flags, struct pt_regs *regs) unsigned char data, unsigned int flags, struct pt_regs *regs)
{ {
struct psmouse *psmouse = serio->private; struct psmouse *psmouse = serio->private;
psmouse_ret_t rc;
if (psmouse->state == PSMOUSE_IGNORE) if (psmouse->state == PSMOUSE_IGNORE)
goto out; goto out;
...@@ -180,7 +190,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, ...@@ -180,7 +190,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
if (psmouse->pktcnt == 2) { if (psmouse->pktcnt == 2) {
if (psmouse->packet[1] == PSMOUSE_RET_ID) { if (psmouse->packet[1] == PSMOUSE_RET_ID) {
psmouse->state = PSMOUSE_IGNORE; psmouse->state = PSMOUSE_IGNORE;
serio_rescan(serio); serio_reconnect(serio);
goto out; goto out;
} }
if (psmouse->type == PSMOUSE_SYNAPTICS) { if (psmouse->type == PSMOUSE_SYNAPTICS) {
...@@ -193,19 +203,32 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, ...@@ -193,19 +203,32 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
} }
} }
if (psmouse->type == PSMOUSE_SYNAPTICS) { rc = psmouse->protocol_handler(psmouse, regs);
/*
* The synaptics driver has its own resync logic, switch (rc) {
* so it needs to receive all bytes one at a time. case PSMOUSE_BAD_DATA:
*/ printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n",
synaptics_process_byte(psmouse, regs); psmouse->name, psmouse->phys, psmouse->pktcnt);
goto out; psmouse->pktcnt = 0;
if (++psmouse->out_of_sync == psmouse_resetafter) {
psmouse->state = PSMOUSE_IGNORE;
printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n");
serio_reconnect(psmouse->serio);
} }
break;
if (psmouse->pktcnt == 3 + (psmouse->type >= PSMOUSE_GENPS)) { case PSMOUSE_FULL_PACKET:
psmouse_process_packet(psmouse, regs);
psmouse->pktcnt = 0; psmouse->pktcnt = 0;
goto out; if (psmouse->out_of_sync) {
psmouse->out_of_sync = 0;
printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n",
psmouse->name, psmouse->phys);
}
break;
case PSMOUSE_GOOD_DATA:
break;
} }
out: out:
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -288,6 +311,30 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command) ...@@ -288,6 +311,30 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command)
} }
/*
* psmouse_sliced_command() sends an extended PS/2 command to the mouse
* using sliced syntax, understood by advanced devices, such as Logitech
* or Synaptics touchpads. The command is encoded as:
* 0xE6 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu
* is the command.
*/
int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command)
{
int i;
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11))
return -1;
for (i = 6; i >= 0; i -= 2) {
unsigned char d = (command >> i) & 3;
if (psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES))
return -1;
}
return 0;
}
/* /*
* psmouse_reset() resets the mouse into power-on state. * psmouse_reset() resets the mouse into power-on state.
*/ */
...@@ -363,31 +410,31 @@ static int im_explorer_detect(struct psmouse *psmouse) ...@@ -363,31 +410,31 @@ static int im_explorer_detect(struct psmouse *psmouse)
* the mouse may have. * the mouse may have.
*/ */
static int psmouse_extensions(struct psmouse *psmouse) static int psmouse_extensions(struct psmouse *psmouse,
unsigned int max_proto, int set_properties)
{ {
int synaptics_hardware = 0; int synaptics_hardware = 0;
psmouse->vendor = "Generic";
psmouse->name = "Mouse";
psmouse->model = 0;
/* /*
* Try Synaptics TouchPad * Try Synaptics TouchPad
*/ */
if (psmouse_max_proto > PSMOUSE_PS2 && synaptics_detect(psmouse)) { if (max_proto > PSMOUSE_PS2 && synaptics_detect(psmouse)) {
synaptics_hardware = 1; synaptics_hardware = 1;
if (set_properties) {
psmouse->vendor = "Synaptics"; psmouse->vendor = "Synaptics";
psmouse->name = "TouchPad"; psmouse->name = "TouchPad";
}
if (psmouse_max_proto > PSMOUSE_IMEX) { if (max_proto > PSMOUSE_IMEX) {
if (synaptics_init(psmouse) == 0) if (!set_properties || synaptics_init(psmouse) == 0)
return PSMOUSE_SYNAPTICS; return PSMOUSE_SYNAPTICS;
/* /*
* Some Synaptics touchpads can emulate extended protocols (like IMPS/2). * Some Synaptics touchpads can emulate extended protocols (like IMPS/2).
* Unfortunately Logitech/Genius probes confuse some firmware versions so * Unfortunately Logitech/Genius probes confuse some firmware versions so
* we'll have to skip them. * we'll have to skip them.
*/ */
psmouse_max_proto = PSMOUSE_IMEX; max_proto = PSMOUSE_IMEX;
} }
/* /*
* Make sure that touchpad is in relative mode, gestures (taps) are enabled * Make sure that touchpad is in relative mode, gestures (taps) are enabled
...@@ -395,35 +442,46 @@ static int psmouse_extensions(struct psmouse *psmouse) ...@@ -395,35 +442,46 @@ static int psmouse_extensions(struct psmouse *psmouse)
synaptics_reset(psmouse); synaptics_reset(psmouse);
} }
if (psmouse_max_proto > PSMOUSE_IMEX && genius_detect(psmouse)) { if (max_proto > PSMOUSE_IMEX && genius_detect(psmouse)) {
if (set_properties) {
set_bit(BTN_EXTRA, psmouse->dev.keybit); set_bit(BTN_EXTRA, psmouse->dev.keybit);
set_bit(BTN_SIDE, psmouse->dev.keybit); set_bit(BTN_SIDE, psmouse->dev.keybit);
set_bit(REL_WHEEL, psmouse->dev.relbit); set_bit(REL_WHEEL, psmouse->dev.relbit);
psmouse->vendor = "Genius"; psmouse->vendor = "Genius";
psmouse->name = "Wheel Mouse"; psmouse->name = "Wheel Mouse";
}
return PSMOUSE_GENPS; return PSMOUSE_GENPS;
} }
if (psmouse_max_proto > PSMOUSE_IMEX) { if (max_proto > PSMOUSE_IMEX) {
int type = ps2pp_detect(psmouse); int type = ps2pp_init(psmouse, set_properties);
if (type) if (type > PSMOUSE_PS2)
return type; return type;
} }
if (psmouse_max_proto >= PSMOUSE_IMPS && intellimouse_detect(psmouse)) { if (max_proto >= PSMOUSE_IMEX && im_explorer_detect(psmouse)) {
set_bit(REL_WHEEL, psmouse->dev.relbit);
if (psmouse_max_proto >= PSMOUSE_IMEX && if (set_properties) {
im_explorer_detect(psmouse)) { set_bit(REL_WHEEL, psmouse->dev.relbit);
set_bit(BTN_SIDE, psmouse->dev.keybit); set_bit(BTN_SIDE, psmouse->dev.keybit);
set_bit(BTN_EXTRA, psmouse->dev.keybit); set_bit(BTN_EXTRA, psmouse->dev.keybit);
if (!psmouse->name)
psmouse->name = "Explorer Mouse"; psmouse->name = "Explorer Mouse";
}
return PSMOUSE_IMEX; return PSMOUSE_IMEX;
} }
if (max_proto >= PSMOUSE_IMPS && intellimouse_detect(psmouse)) {
if (set_properties) {
set_bit(REL_WHEEL, psmouse->dev.relbit);
if (!psmouse->name)
psmouse->name = "Wheel Mouse"; psmouse->name = "Wheel Mouse";
}
return PSMOUSE_IMPS; return PSMOUSE_IMPS;
} }
...@@ -473,12 +531,7 @@ static int psmouse_probe(struct psmouse *psmouse) ...@@ -473,12 +531,7 @@ static int psmouse_probe(struct psmouse *psmouse)
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS)) if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS))
printk(KERN_WARNING "psmouse.c: Failed to reset mouse on %s\n", psmouse->serio->phys); printk(KERN_WARNING "psmouse.c: Failed to reset mouse on %s\n", psmouse->serio->phys);
/* return 0;
* And here we try to determine if it has any extensions over the
* basic PS/2 3-button mouse.
*/
return psmouse->type = psmouse_extensions(psmouse);
} }
/* /*
...@@ -616,7 +669,6 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev) ...@@ -616,7 +669,6 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); 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->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
psmouse->state = PSMOUSE_CMD_MODE; psmouse->state = PSMOUSE_CMD_MODE;
psmouse->serio = serio; psmouse->serio = serio;
psmouse->dev.private = psmouse; psmouse->dev.private = psmouse;
...@@ -628,13 +680,21 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev) ...@@ -628,13 +680,21 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
return; return;
} }
if (psmouse_probe(psmouse) <= 0) { if (psmouse_probe(psmouse) < 0) {
serio_close(serio); serio_close(serio);
kfree(psmouse); kfree(psmouse);
serio->private = NULL; serio->private = NULL;
return; return;
} }
psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1);
if (!psmouse->vendor)
psmouse->vendor = "Generic";
if (!psmouse->name)
psmouse->name = "Mouse";
if (!psmouse->protocol_handler)
psmouse->protocol_handler = psmouse_process_byte;
sprintf(psmouse->devname, "%s %s %s", sprintf(psmouse->devname, "%s %s %s",
psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name); psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name);
sprintf(psmouse->phys, "%s/input0", sprintf(psmouse->phys, "%s/input0",
...@@ -668,27 +728,24 @@ static int psmouse_reconnect(struct serio *serio) ...@@ -668,27 +728,24 @@ static int psmouse_reconnect(struct serio *serio)
{ {
struct psmouse *psmouse = serio->private; struct psmouse *psmouse = serio->private;
struct serio_dev *dev = serio->dev; struct serio_dev *dev = serio->dev;
int old_type;
if (!dev || !psmouse) { if (!dev || !psmouse) {
printk(KERN_DEBUG "psmouse: reconnect request, but serio is disconnected, ignoring...\n"); printk(KERN_DEBUG "psmouse: reconnect request, but serio is disconnected, ignoring...\n");
return -1; return -1;
} }
old_type = psmouse->type;
psmouse->state = PSMOUSE_CMD_MODE; psmouse->state = PSMOUSE_CMD_MODE;
psmouse->type = psmouse->acking = psmouse->cmdcnt = psmouse->pktcnt = 0; psmouse->acking = psmouse->cmdcnt = psmouse->pktcnt = psmouse->out_of_sync = 0;
if (psmouse->reconnect) { if (psmouse->reconnect) {
if (psmouse->reconnect(psmouse)) if (psmouse->reconnect(psmouse))
return -1; return -1;
} else if (psmouse_probe(psmouse) != old_type) } else if (psmouse_probe(psmouse) < 0 ||
psmouse->type != psmouse_extensions(psmouse, psmouse_max_proto, 0))
return -1; return -1;
/* ok, the device type (and capabilities) match the old one, /* ok, the device type (and capabilities) match the old one,
* we can continue using it, complete intialization * we can continue using it, complete intialization
*/ */
psmouse->type = old_type;
psmouse_initialize(psmouse); psmouse_initialize(psmouse);
if (psmouse->ptport) { if (psmouse->ptport) {
......
...@@ -22,6 +22,13 @@ ...@@ -22,6 +22,13 @@
#define PSMOUSE_ACTIVATED 1 #define PSMOUSE_ACTIVATED 1
#define PSMOUSE_IGNORE 2 #define PSMOUSE_IGNORE 2
/* psmouse protocol handler return codes */
typedef enum {
PSMOUSE_BAD_DATA,
PSMOUSE_GOOD_DATA,
PSMOUSE_FULL_PACKET
} psmouse_ret_t;
struct psmouse; struct psmouse;
struct psmouse_ptport { struct psmouse_ptport {
...@@ -45,6 +52,7 @@ struct psmouse { ...@@ -45,6 +52,7 @@ struct psmouse {
unsigned char type; unsigned char type;
unsigned char model; unsigned char model;
unsigned long last; unsigned long last;
unsigned long out_of_sync;
unsigned char state; unsigned char state;
char acking; char acking;
volatile char ack; volatile char ack;
...@@ -52,6 +60,7 @@ struct psmouse { ...@@ -52,6 +60,7 @@ struct psmouse {
char devname[64]; char devname[64];
char phys[32]; char phys[32];
psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs);
int (*reconnect)(struct psmouse *psmouse); int (*reconnect)(struct psmouse *psmouse);
void (*disconnect)(struct psmouse *psmouse); void (*disconnect)(struct psmouse *psmouse);
}; };
...@@ -65,10 +74,10 @@ struct psmouse { ...@@ -65,10 +74,10 @@ struct psmouse {
#define PSMOUSE_SYNAPTICS 7 #define PSMOUSE_SYNAPTICS 7
int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command); int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command);
int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command);
int psmouse_reset(struct psmouse *psmouse); int psmouse_reset(struct psmouse *psmouse);
extern int psmouse_smartscroll; extern int psmouse_smartscroll;
extern unsigned int psmouse_rate; extern unsigned int psmouse_rate;
extern unsigned int psmouse_resetafter;
#endif /* _PSMOUSE_H */ #endif /* _PSMOUSE_H */
This diff is collapsed.
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
#ifndef _SYNAPTICS_H #ifndef _SYNAPTICS_H
#define _SYNAPTICS_H #define _SYNAPTICS_H
extern void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs);
extern int synaptics_detect(struct psmouse *psmouse); extern int synaptics_detect(struct psmouse *psmouse);
extern int synaptics_init(struct psmouse *psmouse); extern int synaptics_init(struct psmouse *psmouse);
extern void synaptics_reset(struct psmouse *psmouse); extern void synaptics_reset(struct psmouse *psmouse);
...@@ -44,13 +43,14 @@ extern void synaptics_reset(struct psmouse *psmouse); ...@@ -44,13 +43,14 @@ extern void synaptics_reset(struct psmouse *psmouse);
/* synaptics capability bits */ /* synaptics capability bits */
#define SYN_CAP_EXTENDED(c) ((c) & (1 << 23)) #define SYN_CAP_EXTENDED(c) ((c) & (1 << 23))
#define SYN_CAP_MIDDLE_BUTTON(c) ((c) & (1 << 18))
#define SYN_CAP_PASS_THROUGH(c) ((c) & (1 << 7)) #define SYN_CAP_PASS_THROUGH(c) ((c) & (1 << 7))
#define SYN_CAP_SLEEP(c) ((c) & (1 << 4)) #define SYN_CAP_SLEEP(c) ((c) & (1 << 4))
#define SYN_CAP_FOUR_BUTTON(c) ((c) & (1 << 3)) #define SYN_CAP_FOUR_BUTTON(c) ((c) & (1 << 3))
#define SYN_CAP_MULTIFINGER(c) ((c) & (1 << 1)) #define SYN_CAP_MULTIFINGER(c) ((c) & (1 << 1))
#define SYN_CAP_PALMDETECT(c) ((c) & (1 << 0)) #define SYN_CAP_PALMDETECT(c) ((c) & (1 << 0))
#define SYN_CAP_VALID(c) ((((c) & 0x00ff00) >> 8) == 0x47) #define SYN_CAP_VALID(c) ((((c) & 0x00ff00) >> 8) == 0x47)
#define SYN_EXT_CAP_REQUESTS(c) ((((c) & 0x700000) >> 20) == 1) #define SYN_EXT_CAP_REQUESTS(c) (((c) & 0x700000) >> 20)
#define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12) #define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12)
/* synaptics modes query bits */ /* synaptics modes query bits */
...@@ -86,18 +86,12 @@ struct synaptics_hw_state { ...@@ -86,18 +86,12 @@ struct synaptics_hw_state {
int y; int y;
int z; int z;
int w; int w;
int left; unsigned int left:1;
int right; unsigned int right:1;
int up; unsigned int middle:1;
int down; unsigned int up:1;
int b0; unsigned int down:1;
int b1; unsigned char ext_buttons;
int b2;
int b3;
int b4;
int b5;
int b6;
int b7;
}; };
struct synaptics_data { struct synaptics_data {
...@@ -108,7 +102,6 @@ struct synaptics_data { ...@@ -108,7 +102,6 @@ struct synaptics_data {
unsigned long int identity; /* Identification */ unsigned long int identity; /* Identification */
/* Data for normal processing */ /* Data for normal processing */
unsigned int out_of_sync; /* # of packets out of sync */
int old_w; /* Previous w value */ int old_w; /* Previous w value */
unsigned char pkt_type; /* packet type - old, new, etc */ unsigned char pkt_type; /* packet type - old, new, etc */
}; };
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
* Input driver to ExplorerPS/2 device driver module. * Input driver to ExplorerPS/2 device driver module.
* *
* Copyright (c) 1999-2002 Vojtech Pavlik * Copyright (c) 1999-2002 Vojtech Pavlik
* Copyright (c) 2004 Dmitry Torokhov
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as published by
...@@ -47,15 +48,24 @@ static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y; ...@@ -47,15 +48,24 @@ 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");
struct mousedev_motion {
int dx, dy, dz;
};
struct mousedev { struct mousedev {
int exist; int exist;
int open; int open;
int minor; int minor;
int misc;
char name[16]; char name[16];
wait_queue_head_t wait; wait_queue_head_t wait;
struct list_head list; struct list_head list;
struct input_handle handle; struct input_handle handle;
struct mousedev_motion packet;
unsigned long buttons;
unsigned int pkt_count;
int old_x[4], old_y[4];
unsigned int touch;
}; };
struct mousedev_list { struct mousedev_list {
...@@ -63,13 +73,10 @@ struct mousedev_list { ...@@ -63,13 +73,10 @@ struct mousedev_list {
struct mousedev *mousedev; struct mousedev *mousedev;
struct list_head node; struct list_head node;
int dx, dy, dz; int dx, dy, dz;
int old_x[4], old_y[4];
unsigned long buttons; unsigned long buttons;
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 mode, imexseq, impsseq;
unsigned int pkt_count;
unsigned char touch;
}; };
#define MOUSEDEV_SEQ_LEN 6 #define MOUSEDEV_SEQ_LEN 6
...@@ -82,135 +89,157 @@ static struct input_handler mousedev_handler; ...@@ -82,135 +89,157 @@ static struct input_handler mousedev_handler;
static struct mousedev *mousedev_table[MOUSEDEV_MINORS]; static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
static struct mousedev mousedev_mix; static struct mousedev mousedev_mix;
#define fx(i) (list->old_x[(list->pkt_count - (i)) & 03]) #define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
#define fy(i) (list->old_y[(list->pkt_count - (i)) & 03]) #define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03])
static void mousedev_abs_event(struct input_handle *handle, struct mousedev_list *list, unsigned int code, int value) static void mousedev_touchpad_event(struct mousedev *mousedev, unsigned int code, int value)
{ {
int size; if (mousedev->touch) {
int touchpad;
/* Ignore joysticks */
if (test_bit(BTN_TRIGGER, handle->dev->keybit))
return;
touchpad = test_bit(BTN_TOOL_FINGER, handle->dev->keybit);
switch (code) { switch (code) {
case ABS_X: case ABS_X:
if (touchpad) {
if (list->touch) {
fx(0) = value; fx(0) = value;
if (list->pkt_count >= 2) if (mousedev->pkt_count >= 2)
list->dx = ((fx(0) - fx(1)) / 2 + (fx(1) - fx(2)) / 2) / 8; mousedev->packet.dx = ((fx(0) - fx(1)) / 2 + (fx(1) - fx(2)) / 2) / 8;
}
} else {
size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X];
if (size == 0) size = xres;
list->dx += (value * xres - list->old_x[0]) / size;
list->old_x[0] += list->dx * size;
}
break; break;
case ABS_Y: case ABS_Y:
if (touchpad) {
if (list->touch) {
fy(0) = value; fy(0) = value;
if (list->pkt_count >= 2) if (mousedev->pkt_count >= 2)
list->dy = -((fy(0) - fy(1)) / 2 + (fy(1) - fy(2)) / 2) / 8; mousedev->packet.dy = -((fy(0) - fy(1)) / 2 + (fy(1) - fy(2)) / 2) / 8;
}
} else {
size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y];
if (size == 0) size = yres;
list->dy -= (value * yres - list->old_y[0]) / size;
list->old_y[0] -= list->dy * size;
}
break; break;
} }
}
} }
static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, unsigned int code, int value)
{ {
struct mousedev *mousedevs[3] = { handle->private, &mousedev_mix, NULL }; int size;
struct mousedev **mousedev = mousedevs;
struct mousedev_list *list;
int index, wake;
while (*mousedev) {
wake = 0; switch (code) {
case ABS_X:
size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
if (size == 0) size = xres;
mousedev->packet.dx = (value * xres - mousedev->old_x[0]) / size;
mousedev->old_x[0] = mousedev->packet.dx * size;
break;
list_for_each_entry(list, &(*mousedev)->list, node) case ABS_Y:
switch (type) { size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y];
case EV_ABS: if (size == 0) size = yres;
mousedev_abs_event(handle, list, code, value); mousedev->packet.dy = (value * yres - mousedev->old_y[0]) / size;
mousedev->old_y[0] = mousedev->packet.dy * size;
break; break;
}
}
case EV_REL: static void mousedev_rel_event(struct mousedev *mousedev, unsigned int code, int value)
{
switch (code) { switch (code) {
case REL_X: list->dx += value; break; case REL_X: mousedev->packet.dx += value; break;
case REL_Y: list->dy -= value; break; case REL_Y: mousedev->packet.dy -= value; break;
case REL_WHEEL: if (list->mode) list->dz -= value; break; case REL_WHEEL: mousedev->packet.dz -= value; break;
} }
break; }
case EV_KEY: static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int value)
if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) { {
/* Handle touchpad data */ int index;
list->touch = value;
if (!list->touch)
list->pkt_count = 0;
break;
}
switch (code) { switch (code) {
case BTN_TOUCH: case BTN_TOUCH:
case BTN_0: case BTN_0:
case BTN_FORWARD: case BTN_FORWARD:
case BTN_LEFT: index = 0; break; case BTN_LEFT: index = 0; break;
case BTN_4:
case BTN_EXTRA: if (list->mode == 2) { index = 4; break; }
case BTN_STYLUS: case BTN_STYLUS:
case BTN_1: case BTN_1:
case BTN_RIGHT: index = 1; break; case BTN_RIGHT: index = 1; break;
case BTN_3:
case BTN_BACK:
case BTN_SIDE: if (list->mode == 2) { index = 3; break; }
case BTN_2: case BTN_2:
case BTN_STYLUS2: case BTN_STYLUS2:
case BTN_MIDDLE: index = 2; break; 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; default: return;
} }
switch (value) {
case 0: clear_bit(index, &list->buttons); break;
case 1: set_bit(index, &list->buttons); break;
case 2: return;
}
break;
case EV_SYN: if (value) {
switch (code) { set_bit(index, &mousedev->buttons);
case SYN_REPORT: set_bit(index, &mousedev_mix.buttons);
if (list->touch) { } else {
list->pkt_count++; clear_bit(index, &mousedev->buttons);
/* Input system eats duplicate events, clear_bit(index, &mousedev_mix.buttons);
* but we need all of them to do correct
* averaging so apply present one forward
*/
fx(0) = fx(1);
fy(0) = fy(1);
} }
}
static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_motion *packet)
{
struct mousedev_list *list;
list_for_each_entry(list, &mousedev->list, node) {
list->dx += packet->dx;
list->dy += packet->dy;
list->dz += packet->dz;
list->buttons = mousedev->buttons;
list->ready = 1; list->ready = 1;
kill_fasync(&list->fasync, SIGIO, POLL_IN); kill_fasync(&list->fasync, SIGIO, POLL_IN);
wake = 1; }
wake_up_interruptible(&mousedev->wait);
}
static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
struct mousedev *mousedev = handle->private;
switch (type) {
case EV_ABS:
/* Ignore joysticks */
if (test_bit(BTN_TRIGGER, handle->dev->keybit))
return;
if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
mousedev_touchpad_event(mousedev, code, value);
else
mousedev_abs_event(handle->dev, mousedev, code, value);
break; break;
case EV_REL:
mousedev_rel_event(mousedev, code, value);
break;
case EV_KEY:
if (value != 2) {
if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) {
/* Handle touchpad data */
mousedev->touch = value;
if (!mousedev->touch)
mousedev->pkt_count = 0;
} }
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);
} }
if (wake) mousedev_notify_readers(mousedev, &mousedev->packet);
wake_up_interruptible(&((*mousedev)->wait)); mousedev_notify_readers(&mousedev_mix, &mousedev->packet);
mousedev++; memset(&mousedev->packet, 0, sizeof(struct mousedev_motion));
}
break;
} }
} }
...@@ -326,6 +355,8 @@ static void mousedev_packet(struct mousedev_list *list, unsigned char off) ...@@ -326,6 +355,8 @@ static void mousedev_packet(struct mousedev_list *list, unsigned char off)
list->dz -= list->ps2[off + 3]; list->dz -= list->ps2[off + 3];
list->ps2[off + 3] = (list->ps2[off + 3] & 0x0f) | ((list->buttons & 0x18) << 1); list->ps2[off + 3] = (list->ps2[off + 3] & 0x0f) | ((list->buttons & 0x18) << 1);
list->bufsiz++; list->bufsiz++;
} else {
list->ps2[off] |= ((list->buttons & 0x10) >> 3) | ((list->buttons & 0x08) >> 1);
} }
if (list->mode == 1) { if (list->mode == 1) {
...@@ -391,9 +422,9 @@ static ssize_t mousedev_write(struct file * file, const char __user * buffer, si ...@@ -391,9 +422,9 @@ static ssize_t mousedev_write(struct file * file, const char __user * buffer, si
list->impsseq = 0; list->impsseq = 0;
list->imexseq = 0; list->imexseq = 0;
list->mode = 0; list->mode = 0;
list->ps2[0] = 0xaa; list->ps2[1] = 0xaa;
list->ps2[1] = 0x00; list->ps2[2] = 0x00;
list->bufsiz = 2; list->bufsiz = 3;
break; break;
} }
...@@ -553,6 +584,7 @@ static struct input_handler mousedev_handler = { ...@@ -553,6 +584,7 @@ static struct input_handler mousedev_handler = {
static struct miscdevice psaux_mouse = { static struct miscdevice psaux_mouse = {
PSMOUSE_MINOR, "psaux", &mousedev_fops PSMOUSE_MINOR, "psaux", &mousedev_fops
}; };
static int psaux_registered;
#endif #endif
static int __init mousedev_init(void) static int __init mousedev_init(void)
...@@ -572,7 +604,7 @@ static int __init mousedev_init(void) ...@@ -572,7 +604,7 @@ static int __init mousedev_init(void)
NULL, "mice"); NULL, "mice");
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
if (!(mousedev_mix.misc = !misc_register(&psaux_mouse))) if (!(psaux_registered = !misc_register(&psaux_mouse)))
printk(KERN_WARNING "mice: could not misc_register the device\n"); printk(KERN_WARNING "mice: could not misc_register the device\n");
#endif #endif
...@@ -584,7 +616,7 @@ static int __init mousedev_init(void) ...@@ -584,7 +616,7 @@ static int __init mousedev_init(void)
static void __exit mousedev_exit(void) static void __exit mousedev_exit(void)
{ {
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
if (mousedev_mix.misc) if (psaux_registered)
misc_deregister(&psaux_mouse); misc_deregister(&psaux_mouse);
#endif #endif
devfs_remove("input/mice"); devfs_remove("input/mice");
......
...@@ -172,3 +172,4 @@ module_exit(power_exit); ...@@ -172,3 +172,4 @@ module_exit(power_exit);
MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>"); MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
MODULE_DESCRIPTION("Input Power Management driver"); MODULE_DESCRIPTION("Input Power Management driver");
MODULE_LICENSE("GPL");
...@@ -51,7 +51,7 @@ spinlock_t kbd98io_lock = SPIN_LOCK_UNLOCKED; ...@@ -51,7 +51,7 @@ spinlock_t kbd98io_lock = SPIN_LOCK_UNLOCKED;
static struct serio kbd98_port; static struct serio kbd98_port;
extern struct pt_regs *kbd_pt_regs; extern struct pt_regs *kbd_pt_regs;
static void kbd98io_interrupt(int irq, void *dev_id, struct pt_regs *regs); static irqreturn_t kbd98io_interrupt(int irq, void *dev_id, struct pt_regs *regs);
/* /*
* kbd98_flush() flushes all data that may be in the keyboard buffers * kbd98_flush() flushes all data that may be in the keyboard buffers
...@@ -143,7 +143,7 @@ static struct serio kbd98_port = ...@@ -143,7 +143,7 @@ static struct serio kbd98_port =
* to the upper layers. * to the upper layers.
*/ */
static void kbd98io_interrupt(int irq, void *dev_id, struct pt_regs *regs) static irqreturn_t kbd98io_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{ {
unsigned long flags; unsigned long flags;
unsigned char data; unsigned char data;
...@@ -154,6 +154,7 @@ static void kbd98io_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -154,6 +154,7 @@ static void kbd98io_interrupt(int irq, void *dev_id, struct pt_regs *regs)
spin_unlock_irqrestore(&kbd98io_lock, flags); spin_unlock_irqrestore(&kbd98io_lock, flags);
serio_interrupt(&kbd98_port, data, 0, regs); serio_interrupt(&kbd98_port, data, 0, regs);
return IRQ_HANDLED;
} }
int __init kbd98io_init(void) int __init kbd98io_init(void)
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
* i8042 keyboard and mouse controller driver for Linux * i8042 keyboard and mouse controller driver for Linux
* *
* Copyright (c) 1999-2002 Vojtech Pavlik * Copyright (c) 1999-2002 Vojtech Pavlik
* Copyright (c) 2004 Dmitry Torokhov
*/ */
/* /*
...@@ -74,6 +75,14 @@ struct i8042_values { ...@@ -74,6 +75,14 @@ struct i8042_values {
unsigned char *phys; unsigned char *phys;
}; };
#define I8042_QUEUE_LEN 64
struct {
unsigned char str[I8042_QUEUE_LEN];
unsigned char data[I8042_QUEUE_LEN];
unsigned int read_pos;
unsigned int write_pos;
} i8042_buf;
static struct serio i8042_kbd_port; static struct serio i8042_kbd_port;
static struct serio i8042_aux_port; static struct serio i8042_aux_port;
static unsigned char i8042_initial_ctr; static unsigned char i8042_initial_ctr;
...@@ -82,7 +91,7 @@ static unsigned char i8042_mux_open; ...@@ -82,7 +91,7 @@ static unsigned char i8042_mux_open;
static unsigned char i8042_mux_present; static unsigned char i8042_mux_present;
static unsigned char i8042_sysdev_initialized; static unsigned char i8042_sysdev_initialized;
static struct pm_dev *i8042_pm_dev; static struct pm_dev *i8042_pm_dev;
struct timer_list i8042_timer; static struct timer_list i8042_timer;
/* /*
* Shared IRQ's require a device pointer, but this driver doesn't support * Shared IRQ's require a device pointer, but this driver doesn't support
...@@ -374,31 +383,28 @@ static char i8042_mux_short[4][16]; ...@@ -374,31 +383,28 @@ static char i8042_mux_short[4][16];
static char i8042_mux_phys[4][32]; static char i8042_mux_phys[4][32];
/* /*
* i8042_interrupt() is the most important function in this driver - * i8042_handle_data() is the most important function in this driver -
* it handles the interrupts from the i8042, and sends incoming bytes * it processes data received by i8042_interrupt and sends it to the
* to the upper layers. * upper layers.
*/ */
static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) static void i8042_handle_data(unsigned long notused)
{ {
unsigned long flags;
unsigned char str, data = 0; unsigned char str, data = 0;
unsigned int dfl; unsigned int dfl;
int ret;
mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); /*
* No locking it required on i8042_buf as the tasklet is guaranteed
* to be serialized and if write_pos changes while comparing it with
* read_pos another run will be scheduled by i8042_interrupt.
*/
while (i8042_buf.read_pos != i8042_buf.write_pos) {
spin_lock_irqsave(&i8042_lock, flags); str = i8042_buf.str[i8042_buf.read_pos];
str = i8042_read_status(); data = i8042_buf.data[i8042_buf.read_pos];
if (str & I8042_STR_OBF)
data = i8042_read_data();
spin_unlock_irqrestore(&i8042_lock, flags);
if (~str & I8042_STR_OBF) { i8042_buf.read_pos++;
if (irq) dbg("Interrupt %d, without any data", irq); i8042_buf.read_pos %= I8042_QUEUE_LEN;
ret = 0;
goto out;
}
dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) | dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) |
((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0); ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0);
...@@ -419,32 +425,67 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -419,32 +425,67 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs)
dfl & SERIO_PARITY ? ", bad parity" : "", dfl & SERIO_PARITY ? ", bad parity" : "",
dfl & SERIO_TIMEOUT ? ", timeout" : ""); dfl & SERIO_TIMEOUT ? ", timeout" : "");
serio_interrupt(i8042_mux_port + ((str >> 6) & 3), data, dfl, regs); serio_interrupt(i8042_mux_port + ((str >> 6) & 3), data, dfl, NULL);
} else {
goto irq_ret;
}
dbg("%02x <- i8042 (interrupt, %s, %d%s%s)", dbg("%02x <- i8042 (interrupt, %s, %d%s%s)",
data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", irq, data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", irq,
dfl & SERIO_PARITY ? ", bad parity" : "", dfl & SERIO_PARITY ? ", bad parity" : "",
dfl & SERIO_TIMEOUT ? ", timeout" : ""); dfl & SERIO_TIMEOUT ? ", timeout" : "");
if (i8042_aux_values.exists && (str & I8042_STR_AUXDATA)) { if (i8042_aux_values.exists && (str & I8042_STR_AUXDATA))
serio_interrupt(&i8042_aux_port, data, dfl, regs); serio_interrupt(&i8042_aux_port, data, dfl, NULL);
goto irq_ret; else if (i8042_kbd_values.exists)
serio_interrupt(&i8042_kbd_port, data, dfl, NULL);
}
}
}
DECLARE_TASKLET(i8042_tasklet, i8042_handle_data, 0);
/*
* i8042_interrupt() handles the interrupts from i8042 and schedules
* i8042_handle_data to process and pass received bytes to the upper
* layers.
*/
static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned long flags;
unsigned char str;
unsigned int n_bytes = 0;
mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
spin_lock_irqsave(&i8042_lock, flags);
while ((str = i8042_read_status()) & I8042_STR_OBF) {
n_bytes++;
i8042_buf.str[i8042_buf.write_pos] = str;
i8042_buf.data[i8042_buf.write_pos] = i8042_read_data();
i8042_buf.write_pos++;
i8042_buf.write_pos %= I8042_QUEUE_LEN;
if (unlikely(i8042_buf.write_pos == i8042_buf.read_pos))
printk(KERN_WARNING "i8042.c: ring buffer full\n");
} }
if (!i8042_kbd_values.exists) spin_unlock_irqrestore(&i8042_lock, flags);
goto irq_ret;
if (unlikely(n_bytes == 0)) {
if (irq) dbg("Interrupt %d, without any data", irq);
return IRQ_NONE;
}
serio_interrupt(&i8042_kbd_port, data, dfl, regs); tasklet_schedule(&i8042_tasklet);
irq_ret: return IRQ_HANDLED;
ret = 1;
out:
return IRQ_RETVAL(ret);
} }
/* /*
* i8042_enable_mux_mode checks whether the controller has an active * i8042_enable_mux_mode checks whether the controller has an active
* multiplexor and puts the chip into Multiplexed (as opposed to * multiplexor and puts the chip into Multiplexed (as opposed to
...@@ -474,8 +515,17 @@ static int i8042_enable_mux_mode(struct i8042_values *values, unsigned char *mux ...@@ -474,8 +515,17 @@ static int i8042_enable_mux_mode(struct i8042_values *values, unsigned char *mux
if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0xa9) if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0xa9)
return -1; return -1;
param = 0xa4; param = 0xa4;
if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param == 0x5b) if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param == 0x5b) {
/*
* Do another loop test with the 0x5a value. Doing anything else upsets
* Profusion/ServerWorks OSB4 chipsets.
*/
param = 0x5a;
i8042_command(&param, I8042_CMD_AUX_LOOP);
return -1; return -1;
}
if (mux_version) if (mux_version)
*mux_version = ~param; *mux_version = ~param;
...@@ -532,8 +582,8 @@ static int __init i8042_check_mux(struct i8042_values *values) ...@@ -532,8 +582,8 @@ static int __init i8042_check_mux(struct i8042_values *values)
return -1; return -1;
/* Workaround for broken chips which seem to support MUX, but in reality don't. */ /* Workaround for broken chips which seem to support MUX, but in reality don't. */
/* They all report version 12.10 */ /* They all report version 10.12 */
if (mux_version == 0xCA) if (mux_version == 0xAC)
return -1; return -1;
printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n", printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n",
...@@ -868,7 +918,7 @@ static int i8042_controller_resume(void) ...@@ -868,7 +918,7 @@ static int i8042_controller_resume(void)
static int i8042_notify_sys(struct notifier_block *this, unsigned long code, static int i8042_notify_sys(struct notifier_block *this, unsigned long code,
void *unused) void *unused)
{ {
if (code==SYS_DOWN || code==SYS_HALT) if (code == SYS_DOWN || code == SYS_HALT)
i8042_controller_cleanup(); i8042_controller_cleanup();
return NOTIFY_DONE; return NOTIFY_DONE;
} }
...@@ -997,8 +1047,6 @@ void __exit i8042_exit(void) ...@@ -997,8 +1047,6 @@ void __exit i8042_exit(void)
sysdev_class_unregister(&kbc_sysclass); sysdev_class_unregister(&kbc_sysclass);
} }
del_timer_sync(&i8042_timer);
i8042_controller_cleanup(); i8042_controller_cleanup();
if (i8042_kbd_values.exists) if (i8042_kbd_values.exists)
...@@ -1011,6 +1059,9 @@ void __exit i8042_exit(void) ...@@ -1011,6 +1059,9 @@ void __exit i8042_exit(void)
if (i8042_mux_values[i].exists) if (i8042_mux_values[i].exists)
serio_unregister_port(i8042_mux_port + i); serio_unregister_port(i8042_mux_port + i);
del_timer_sync(&i8042_timer);
tasklet_kill(&i8042_tasklet);
i8042_platform_exit(); i8042_platform_exit();
} }
......
...@@ -86,20 +86,9 @@ static int parkbd_write(struct serio *port, unsigned char c) ...@@ -86,20 +86,9 @@ static int parkbd_write(struct serio *port, unsigned char c)
return 0; return 0;
} }
static int parkbd_open(struct serio *port)
{
return 0;
}
static void parkbd_close(struct serio *port)
{
}
static struct serio parkbd_port = static struct serio parkbd_port =
{ {
.write = parkbd_write, .write = parkbd_write,
.open = parkbd_open,
.close = parkbd_close,
.name = parkbd_name, .name = parkbd_name,
.phys = parkbd_phys, .phys = parkbd_phys,
}; };
......
...@@ -47,23 +47,12 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); ...@@ -47,23 +47,12 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Q40 PS/2 keyboard controller driver"); MODULE_DESCRIPTION("Q40 PS/2 keyboard controller driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static int q40kbd_open(struct serio *port)
{
return 0;
}
static void q40kbd_close(struct serio *port)
{
}
static struct serio q40kbd_port = static struct serio q40kbd_port =
{ {
.type = SERIO_8042, .type = SERIO_8042,
.name = "Q40 kbd port", .name = "Q40 kbd port",
.phys = "Q40", .phys = "Q40",
.write = NULL, .write = NULL,
.open = q40kbd_open,
.close = q40kbd_close,
}; };
static irqreturn_t q40kbd_interrupt(int irq, void *dev_id, static irqreturn_t q40kbd_interrupt(int irq, void *dev_id,
......
...@@ -293,7 +293,7 @@ void serio_unregister_device(struct serio_dev *dev) ...@@ -293,7 +293,7 @@ void serio_unregister_device(struct serio_dev *dev)
int serio_open(struct serio *serio, struct serio_dev *dev) int serio_open(struct serio *serio, struct serio_dev *dev)
{ {
serio->dev = dev; serio->dev = dev;
if (serio->open(serio)) { if (serio->open && serio->open(serio)) {
serio->dev = NULL; serio->dev = NULL;
return -1; return -1;
} }
...@@ -303,6 +303,7 @@ int serio_open(struct serio *serio, struct serio_dev *dev) ...@@ -303,6 +303,7 @@ int serio_open(struct serio *serio, struct serio_dev *dev)
/* called from serio_dev->connect/disconnect methods under serio_sem */ /* called from serio_dev->connect/disconnect methods under serio_sem */
void serio_close(struct serio *serio) void serio_close(struct serio *serio)
{ {
if (serio->close)
serio->close(serio); serio->close(serio);
serio->dev = NULL; serio->dev = NULL;
} }
......
...@@ -48,11 +48,6 @@ static int serport_serio_write(struct serio *serio, unsigned char data) ...@@ -48,11 +48,6 @@ static int serport_serio_write(struct serio *serio, unsigned char data)
return -(serport->tty->driver->write(serport->tty, 0, &data, 1) != 1); return -(serport->tty->driver->write(serport->tty, 0, &data, 1) != 1);
} }
static int serport_serio_open(struct serio *serio)
{
return 0;
}
static void serport_serio_close(struct serio *serio) static void serport_serio_close(struct serio *serio)
{ {
struct serport *serport = serio->driver; struct serport *serport = serio->driver;
...@@ -87,7 +82,6 @@ static int serport_ldisc_open(struct tty_struct *tty) ...@@ -87,7 +82,6 @@ static int serport_ldisc_open(struct tty_struct *tty)
serport->serio.type = SERIO_RS232; serport->serio.type = SERIO_RS232;
serport->serio.write = serport_serio_write; serport->serio.write = serport_serio_write;
serport->serio.open = serport_serio_open;
serport->serio.close = serport_serio_close; serport->serio.close = serport_serio_close;
serport->serio.driver = serport; serport->serio.driver = serport;
......
...@@ -125,11 +125,9 @@ static void gunze_connect(struct serio *serio, struct serio_dev *dev) ...@@ -125,11 +125,9 @@ static void gunze_connect(struct serio *serio, struct serio_dev *dev)
init_input_dev(&gunze->dev); init_input_dev(&gunze->dev);
gunze->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); gunze->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
gunze->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
gunze->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); gunze->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
input_set_abs_params(&gunze->dev, ABS_X, 96, 4000, 0, 0);
gunze->dev.absmin[ABS_X] = 96; gunze->dev.absmin[ABS_Y] = 72; input_set_abs_params(&gunze->dev, ABS_Y, 72, 3000, 0, 0);
gunze->dev.absmax[ABS_X] = 4000; gunze->dev.absmax[ABS_Y] = 3000;
gunze->serio = serio; gunze->serio = serio;
serio->private = gunze; serio->private = gunze;
......
...@@ -45,6 +45,10 @@ ...@@ -45,6 +45,10 @@
#include <asm/arch/hardware.h> #include <asm/arch/hardware.h>
#include <asm/arch/irqs.h> #include <asm/arch/irqs.h>
MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
MODULE_DESCRIPTION("H3600 touchscreen driver");
MODULE_LICENSE("GPL");
/* /*
* Definitions & global arrays. * Definitions & global arrays.
*/ */
...@@ -103,7 +107,7 @@ struct h3600_dev { ...@@ -103,7 +107,7 @@ struct h3600_dev {
char phys[32]; char phys[32];
}; };
static void action_button_handler(int irq, void *dev_id, struct pt_regs *regs) static irqreturn_t action_button_handler(int irq, void *dev_id, struct pt_regs *regs)
{ {
int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1; int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1;
struct input_dev *dev = (struct input_dev *) dev_id; struct input_dev *dev = (struct input_dev *) dev_id;
...@@ -111,9 +115,11 @@ static void action_button_handler(int irq, void *dev_id, struct pt_regs *regs) ...@@ -111,9 +115,11 @@ static void action_button_handler(int irq, void *dev_id, struct pt_regs *regs)
input_regs(dev, regs); input_regs(dev, regs);
input_report_key(dev, KEY_ENTER, down); input_report_key(dev, KEY_ENTER, down);
input_sync(dev); input_sync(dev);
return IRQ_HANDLED;
} }
static void npower_button_handler(int irq, void *dev_id, struct pt_regs *regs) static irqreturn_t npower_button_handler(int irq, void *dev_id, struct pt_regs *regs)
{ {
int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1; int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1;
struct input_dev *dev = (struct input_dev *) dev_id; struct input_dev *dev = (struct input_dev *) dev_id;
...@@ -126,6 +132,8 @@ static void npower_button_handler(int irq, void *dev_id, struct pt_regs *regs) ...@@ -126,6 +132,8 @@ static void npower_button_handler(int irq, void *dev_id, struct pt_regs *regs)
input_report_key(dev, KEY_SUSPEND, 1); input_report_key(dev, KEY_SUSPEND, 1);
input_report_key(dev, KEY_SUSPEND, down); input_report_key(dev, KEY_SUSPEND, down);
input_sync(dev); input_sync(dev);
return IRQ_HANDLED;
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
...@@ -141,7 +149,7 @@ enum flite_pwr { ...@@ -141,7 +149,7 @@ enum flite_pwr {
* h3600_flite_power: enables or disables power to frontlight, using last bright */ * h3600_flite_power: enables or disables power to frontlight, using last bright */
unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr) unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr)
{ {
unsigned char brightness = ((pwr==FLITE_PWR_OFF) ? 0:flite_brightness); unsigned char brightness = (pwr == FLITE_PWR_OFF) ? 0 : flite_brightness;
struct h3600_dev *ts = dev->private; struct h3600_dev *ts = dev->private;
/* Must be in this order */ /* Must be in this order */
...@@ -317,8 +325,8 @@ static int state; ...@@ -317,8 +325,8 @@ static int state;
#define STATE_DATA 2 /* state where we decode data */ #define STATE_DATA 2 /* state where we decode data */
#define STATE_EOF 3 /* state where we decode checksum or EOF */ #define STATE_EOF 3 /* state where we decode checksum or EOF */
static void h3600ts_interrupt(struct serio *serio, unsigned char data, static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data,
unsigned int flags) unsigned int flags, struct pt_regs *regs)
{ {
struct h3600_dev *ts = serio->private; struct h3600_dev *ts = serio->private;
...@@ -329,7 +337,7 @@ static void h3600ts_interrupt(struct serio *serio, unsigned char data, ...@@ -329,7 +337,7 @@ static void h3600ts_interrupt(struct serio *serio, unsigned char data,
case STATE_SOF: case STATE_SOF:
if (data == CHAR_SOF) if (data == CHAR_SOF)
state = STATE_ID; state = STATE_ID;
return; break;
case STATE_ID: case STATE_ID:
ts->event = (data & 0xf0) >> 4; ts->event = (data & 0xf0) >> 4;
ts->len = (data & 0xf); ts->len = (data & 0xf);
...@@ -339,7 +347,7 @@ static void h3600ts_interrupt(struct serio *serio, unsigned char data, ...@@ -339,7 +347,7 @@ static void h3600ts_interrupt(struct serio *serio, unsigned char data,
break; break;
} }
ts->chksum = data; ts->chksum = data;
state=(ts->len > 0 ) ? STATE_DATA : STATE_EOF; state = (ts->len > 0) ? STATE_DATA : STATE_EOF;
break; break;
case STATE_DATA: case STATE_DATA:
ts->chksum += data; ts->chksum += data;
...@@ -349,13 +357,15 @@ static void h3600ts_interrupt(struct serio *serio, unsigned char data, ...@@ -349,13 +357,15 @@ static void h3600ts_interrupt(struct serio *serio, unsigned char data,
break; break;
case STATE_EOF: case STATE_EOF:
state = STATE_SOF; state = STATE_SOF;
if (data == CHAR_EOF || data == ts->chksum ) if (data == CHAR_EOF || data == ts->chksum)
h3600ts_process_packet(ts); h3600ts_process_packet(ts, regs);
break; break;
default: default:
printk("Error3\n"); printk("Error3\n");
break; break;
} }
return IRQ_HANDLED;
} }
/* /*
...@@ -378,8 +388,8 @@ static void h3600ts_connect(struct serio *serio, struct serio_dev *dev) ...@@ -378,8 +388,8 @@ static void h3600ts_connect(struct serio *serio, struct serio_dev *dev)
init_input_dev(&ts->dev); init_input_dev(&ts->dev);
/* Device specific stuff */ /* Device specific stuff */
set_GPIO_IRQ_edge( GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES ); set_GPIO_IRQ_edge(GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES);
set_GPIO_IRQ_edge( GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE ); set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE);
if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler, if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM, SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
...@@ -397,17 +407,12 @@ static void h3600ts_connect(struct serio *serio, struct serio_dev *dev) ...@@ -397,17 +407,12 @@ static void h3600ts_connect(struct serio *serio, struct serio_dev *dev)
kfree(ts); kfree(ts);
return; return;
} }
/* Now we have things going we setup our input device */ /* Now we have things going we setup our input device */
ts->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_LED) | BIT(EV_PWR); ts->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_LED) | BIT(EV_PWR);
ts->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
ts->dev.ledbit[0] = BIT(LED_SLEEP); ts->dev.ledbit[0] = BIT(LED_SLEEP);
input_set_abs_params(&ts->dev, ABS_X, 60, 985, 0, 0);
ts->dev.absmin[ABS_X] = 60; ts->dev.absmin[ABS_Y] = 35; input_set_abs_params(&ts->dev, ABS_Y, 35, 1024, 0, 0);
ts->dev.absmax[ABS_X] = 985; ts->dev.absmax[ABS_Y] = 1024;
ts->dev.absfuzz[ABS_X] = 0; ts->dev.absfuzz[ABS_Y] = 0;
ts->serio = serio;
serio->private = ts;
set_bit(KEY_RECORD, ts->dev.keybit); set_bit(KEY_RECORD, ts->dev.keybit);
set_bit(KEY_Q, ts->dev.keybit); set_bit(KEY_Q, ts->dev.keybit);
...@@ -422,6 +427,9 @@ static void h3600ts_connect(struct serio *serio, struct serio_dev *dev) ...@@ -422,6 +427,9 @@ static void h3600ts_connect(struct serio *serio, struct serio_dev *dev)
ts->dev.keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH); ts->dev.keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH);
ts->dev.keybit[LONG(KEY_SUSPEND)] |= BIT(KEY_SUSPEND); ts->dev.keybit[LONG(KEY_SUSPEND)] |= BIT(KEY_SUSPEND);
ts->serio = serio;
serio->private = ts;
sprintf(ts->phys, "%s/input0", serio->phys); sprintf(ts->phys, "%s/input0", serio->phys);
ts->dev.event = h3600ts_event; ts->dev.event = h3600ts_event;
......
...@@ -749,8 +749,6 @@ struct ff_effect { ...@@ -749,8 +749,6 @@ struct ff_effect {
#define INPUT_KEYCODE(dev, scancode) ((dev->keycodesize == 1) ? ((u8*)dev->keycode)[scancode] : \ #define INPUT_KEYCODE(dev, scancode) ((dev->keycodesize == 1) ? ((u8*)dev->keycode)[scancode] : \
((dev->keycodesize == 2) ? ((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)
#define SET_INPUT_KEYCODE(dev, scancode, val) \ #define SET_INPUT_KEYCODE(dev, scancode, val) \
({ unsigned __old; \ ({ unsigned __old; \
switch (dev->keycodesize) { \ switch (dev->keycodesize) { \
...@@ -915,6 +913,12 @@ struct input_handle { ...@@ -915,6 +913,12 @@ struct input_handle {
#define to_handle(n) container_of(n,struct input_handle,d_node) #define to_handle(n) container_of(n,struct input_handle,d_node)
#define to_handle_h(n) container_of(n,struct input_handle,h_node) #define to_handle_h(n) container_of(n,struct input_handle,h_node)
static inline void init_input_dev(struct input_dev *dev)
{
INIT_LIST_HEAD(&dev->h_list);
INIT_LIST_HEAD(&dev->node);
}
void input_register_device(struct input_dev *); void input_register_device(struct input_dev *);
void input_unregister_device(struct input_dev *); void input_unregister_device(struct input_dev *);
...@@ -932,14 +936,51 @@ int input_flush_device(struct input_handle* handle, struct file* file); ...@@ -932,14 +936,51 @@ int input_flush_device(struct input_handle* handle, struct file* file);
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value); void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
#define input_report_key(a,b,c) input_event(a, EV_KEY, b, !!(c)) static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
#define input_report_rel(a,b,c) input_event(a, EV_REL, b, c) {
#define input_report_abs(a,b,c) input_event(a, EV_ABS, b, c) input_event(dev, EV_KEY, code, !!value);
#define input_report_ff(a,b,c) input_event(a, EV_FF, b, c) }
#define input_report_ff_status(a,b,c) input_event(a, EV_FF_STATUS, b, c)
static inline void input_report_rel(struct input_dev *dev, unsigned int code, int value)
#define input_regs(a,b) do { (a)->regs = (b); } while (0) {
#define input_sync(a) do { input_event(a, EV_SYN, SYN_REPORT, 0); (a)->regs = NULL; } while (0) input_event(dev, EV_REL, code, value);
}
static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_ABS, code, value);
}
static inline void input_report_ff(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_FF, code, value);
}
static inline void input_report_ff_status(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_FF_STATUS, code, value);
}
static inline void input_regs(struct input_dev *dev, struct pt_regs *regs)
{
dev->regs = regs;
}
static inline void input_sync(struct input_dev *dev)
{
input_event(dev, EV_SYN, SYN_REPORT, 0);
dev->regs = NULL;
}
static inline void input_set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat)
{
dev->absmin[axis] = min;
dev->absmax[axis] = max;
dev->absfuzz[axis] = fuzz;
dev->absflat[axis] = flat;
dev->absbit[LONG(axis)] |= BIT(axis);
}
extern struct class_simple *input_class; extern struct class_simple *input_class;
......
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