Commit bb92d1c3 authored by Vojtech Pavlik's avatar Vojtech Pavlik

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

parents 981a1ad3 e7d8f455
......@@ -652,6 +652,12 @@ running once the system is up.
mga= [HW,DRM]
mousedev.tap_time=
[MOUSE] Maximum time between finger touching and
leaving touchpad surface for touch to be considered
a tap and be reported as a left button click (for
touchpads working in absolute mode only).
Format: <msecs>
mousedev.xres= [MOUSE] Horizontal screen resolution, used for devices
reporting absolute coordinates, such as tablets
mousedev.yres= [MOUSE] Vertical screen resolution, used for devices
......
......@@ -15,6 +15,9 @@
unsigned long dmi_broken;
EXPORT_SYMBOL(dmi_broken);
unsigned int i8042_dmi_noloop = 0;
EXPORT_SYMBOL(i8042_dmi_noloop);
int is_sony_vaio_laptop;
int is_unsafe_smbus;
int es7000_plat = 0;
......@@ -400,6 +403,17 @@ static __init int sony_vaio_laptop(struct dmi_blacklist *d)
return 0;
}
/*
* Several HP Proliant (and maybe other OSB4/ProFusion) systems
* shouldn't use the AUX LoopBack command, or they crash or reboot.
*/
static __init int set_8042_noloop(struct dmi_blacklist *d)
{
i8042_dmi_noloop = 1;
return 0;
}
/*
* This bios swaps the APM minute reporting bytes over (Many sony laptops
* have this problem).
......@@ -876,6 +890,23 @@ static __initdata struct dmi_blacklist dmi_blacklist[]={
NO_MATCH, NO_MATCH,
} },
/*
* Several HP Proliant (and maybe other OSB4/ProFusion) systems
* can't use i8042 in mux mode, or they crash or reboot.
*/
{ set_8042_noloop, "Compaq Proliant 8500", {
MATCH(DMI_SYS_VENDOR, "Compaq"),
MATCH(DMI_PRODUCT_NAME , "ProLiant"),
MATCH(DMI_PRODUCT_VERSION, "8500"),
NO_MATCH }},
{ set_8042_noloop, "Compaq Proliant DL760", {
MATCH(DMI_SYS_VENDOR, "Compaq"),
MATCH(DMI_PRODUCT_NAME , "ProLiant"),
MATCH(DMI_PRODUCT_VERSION, "DL760"),
NO_MATCH }},
#ifdef CONFIG_ACPI_BOOT
/*
* If your system is blacklisted here, but you find that acpi=force
......
......@@ -942,6 +942,9 @@ void kbd_refresh_leds(struct input_handle *handle)
#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) || defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64) || defined(CONFIG_PARISC) || defined(CONFIG_SH_MPC1211)
#define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\
((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001))
static unsigned short x86_keycodes[256] =
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
......@@ -1008,6 +1011,8 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode,
#else
#define HW_RAW(dev) 0
#warning "Cannot generate rawmode keyboard for your architecture yet."
static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag)
......@@ -1020,7 +1025,15 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char u
}
#endif
void kbd_keycode(unsigned int keycode, int down, struct pt_regs *regs)
void kbd_rawcode(unsigned char data)
{
struct vc_data *vc = vc_cons[fg_console].d;
kbd = kbd_table + fg_console;
if (kbd->kbdmode == VC_RAW)
put_queue(vc, data);
}
void kbd_keycode(unsigned int keycode, int down, int hw_raw, struct pt_regs *regs)
{
struct vc_data *vc = vc_cons[fg_console].d;
unsigned short keysym, *key_map;
......@@ -1054,7 +1067,7 @@ void kbd_keycode(unsigned int keycode, int down, struct pt_regs *regs)
return;
#endif /* CONFIG_MAC_EMUMOUSEBTN */
if ((raw_mode = (kbd->kbdmode == VC_RAW)))
if ((raw_mode = (kbd->kbdmode == VC_RAW)) && !hw_raw)
if (emulate_raw(vc, keycode, !down << 7))
if (keycode < BTN_MISC)
printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode);
......@@ -1149,11 +1162,12 @@ void kbd_keycode(unsigned int keycode, int down, struct pt_regs *regs)
}
static void kbd_event(struct input_handle *handle, unsigned int event_type,
unsigned int keycode, int down)
unsigned int event_code, int value)
{
if (event_type != EV_KEY)
return;
kbd_keycode(keycode, down, handle->dev->regs);
if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev))
kbd_rawcode(value);
if (event_type == EV_KEY)
kbd_keycode(event_code, value, HW_RAW(handle->dev), handle->dev->regs);
tasklet_schedule(&keyboard_tasklet);
do_poke_blanked_console = 1;
schedule_console_callback();
......
......@@ -47,6 +47,10 @@ static int atkbd_softrepeat;
module_param_named(softrepeat, atkbd_softrepeat, bool, 0);
MODULE_PARM_DESC(softrepeat, "Use software keyboard repeat");
static int atkbd_softraw = 1;
module_param_named(softraw, atkbd_softraw, bool, 0);
MODULE_PARM_DESC(softraw, "Use software generated rawmode");
static int atkbd_scroll;
module_param_named(scroll, atkbd_scroll, bool, 0);
MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards");
......@@ -164,34 +168,48 @@ static unsigned char atkbd_scroll_keys[5][2] = {
{ ATKBD_SCR_CLICK, 0x60 },
};
#define ATKBD_FLAG_ACK 0 /* Waiting for ACK/NAK */
#define ATKBD_FLAG_CMD 1 /* Waiting for command to finish */
#define ATKBD_FLAG_CMD1 2 /* First byte of command response */
#define ATKBD_FLAG_ID 3 /* First byte is not keyboard ID */
#define ATKBD_FLAG_ENABLED 4 /* Waining for init to finish */
/*
* The atkbd control structure
*/
struct atkbd {
unsigned char keycode[512];
struct input_dev dev;
struct serio *serio;
/* Written only during init */
char name[64];
char phys[32];
unsigned short id;
struct serio *serio;
struct input_dev dev;
unsigned char set;
unsigned int translated:1;
unsigned int extra:1;
unsigned int write:1;
unsigned short id;
unsigned char keycode[512];
unsigned char translated;
unsigned char extra;
unsigned char write;
/* Protected by FLAG_ACK */
unsigned char nak;
/* Protected by FLAG_CMD */
unsigned char cmdbuf[4];
unsigned char cmdcnt;
volatile signed char ack;
unsigned char emul;
unsigned int resend:1;
unsigned int release:1;
unsigned int bat_xl:1;
unsigned int enabled:1;
/* Accessed only from interrupt */
unsigned char emul;
unsigned char resend;
unsigned char release;
unsigned char bat_xl;
unsigned int last;
unsigned long time;
/* Flags */
unsigned long flags;
};
static void atkbd_report_key(struct input_dev *dev, struct pt_regs *regs, int code, int value)
......@@ -224,7 +242,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
#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);
printk(KERN_WARNING "atkbd.c: frame/parity error: %02x\n", flags);
serio_write(serio, ATKBD_CMD_RESEND);
atkbd->resend = 1;
goto out;
......@@ -234,24 +252,45 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
atkbd->resend = 0;
#endif
if (!atkbd->ack)
if (test_bit(ATKBD_FLAG_ACK, &atkbd->flags))
switch (code) {
case ATKBD_RET_ACK:
atkbd->ack = 1;
atkbd->nak = 0;
if (atkbd->cmdcnt) {
set_bit(ATKBD_FLAG_CMD, &atkbd->flags);
set_bit(ATKBD_FLAG_CMD1, &atkbd->flags);
set_bit(ATKBD_FLAG_ID, &atkbd->flags);
}
clear_bit(ATKBD_FLAG_ACK, &atkbd->flags);
goto out;
case ATKBD_RET_NAK:
atkbd->ack = -1;
atkbd->nak = 1;
clear_bit(ATKBD_FLAG_ACK, &atkbd->flags);
goto out;
}
if (atkbd->cmdcnt) {
atkbd->cmdbuf[--atkbd->cmdcnt] = code;
if (test_bit(ATKBD_FLAG_CMD, &atkbd->flags)) {
atkbd->cmdcnt--;
atkbd->cmdbuf[atkbd->cmdcnt] = code;
if (atkbd->cmdcnt == 1) {
if (code != 0xab && code != 0xac)
clear_bit(ATKBD_FLAG_ID, &atkbd->flags);
clear_bit(ATKBD_FLAG_CMD1, &atkbd->flags);
}
if (!atkbd->cmdcnt)
clear_bit(ATKBD_FLAG_CMD, &atkbd->flags);
goto out;
}
if (!atkbd->enabled)
if (!test_bit(ATKBD_FLAG_ENABLED, &atkbd->flags))
goto out;
input_event(&atkbd->dev, EV_MSC, MSC_RAW, code);
if (atkbd->translated) {
if (atkbd->emul ||
......@@ -270,6 +309,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
switch (code) {
case ATKBD_RET_BAT:
clear_bit(ATKBD_FLAG_ENABLED, &atkbd->flags);
serio_rescan(atkbd->serio);
goto out;
case ATKBD_RET_EMUL0:
......@@ -300,6 +340,9 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
code |= (atkbd->set != 3) ? 0x80 : 0x100;
}
if (atkbd->keycode[code] != ATKBD_KEY_NULL)
input_event(&atkbd->dev, EV_MSC, MSC_SCAN, code);
switch (atkbd->keycode[code]) {
case ATKBD_KEY_NULL:
break;
......@@ -376,18 +419,20 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
static int atkbd_sendbyte(struct atkbd *atkbd, unsigned char byte)
{
int timeout = 20000; /* 200 msec */
atkbd->ack = 0;
int timeout = 200000; /* 200 msec */
#ifdef ATKBD_DEBUG
printk(KERN_DEBUG "atkbd.c: Sent: %02x\n", byte);
#endif
set_bit(ATKBD_FLAG_ACK, &atkbd->flags);
clear_bit(ATKBD_FLAG_CMD, &atkbd->flags);
if (serio_write(atkbd->serio, byte))
return -1;
while (test_bit(ATKBD_FLAG_ACK, &atkbd->flags) && timeout--) udelay(1);
clear_bit(ATKBD_FLAG_ACK, &atkbd->flags);
while (!atkbd->ack && timeout--) udelay(10);
return -(atkbd->ack <= 0);
return -atkbd->nak;
}
/*
......@@ -405,7 +450,7 @@ static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command)
atkbd->cmdcnt = receive;
if (command == ATKBD_CMD_RESET_BAT)
timeout = 2000000; /* 2 sec */
timeout = 4000000; /* 4 sec */
if (receive && param)
for (i = 0; i < receive; i++)
......@@ -413,38 +458,40 @@ static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command)
if (command & 0xff)
if (atkbd_sendbyte(atkbd, command & 0xff))
return (atkbd->cmdcnt = 0) - 1;
return -1;
for (i = 0; i < send; i++)
if (atkbd_sendbyte(atkbd, param[i]))
return (atkbd->cmdcnt = 0) - 1;
return -1;
while (atkbd->cmdcnt && timeout--) {
while (test_bit(ATKBD_FLAG_CMD, &atkbd->flags) && timeout--) {
if (atkbd->cmdcnt == 1 &&
command == ATKBD_CMD_RESET_BAT && timeout > 100000)
timeout = 100000;
if (!test_bit(ATKBD_FLAG_CMD1, &atkbd->flags)) {
if (command == ATKBD_CMD_RESET_BAT && timeout > 100000)
timeout = 100000;
if (atkbd->cmdcnt == 1 && command == ATKBD_CMD_GETID &&
atkbd->cmdbuf[1] != 0xab && atkbd->cmdbuf[1] != 0xac) {
atkbd->cmdcnt = 0;
break;
if (command == ATKBD_CMD_GETID && !test_bit(ATKBD_FLAG_ID, &atkbd->flags)) {
clear_bit(ATKBD_FLAG_CMD, &atkbd->flags);
atkbd->cmdcnt = 0;
break;
}
}
udelay(1);
}
clear_bit(ATKBD_FLAG_CMD, &atkbd->flags);
if (param)
for (i = 0; i < receive; i++)
param[i] = atkbd->cmdbuf[(receive - 1) - i];
if (command == ATKBD_CMD_RESET_BAT && atkbd->cmdcnt == 1)
atkbd->cmdcnt = 0;
return 0;
if (atkbd->cmdcnt) {
atkbd->cmdcnt = 0;
if (atkbd->cmdcnt)
return -1;
}
return 0;
}
......@@ -672,6 +719,7 @@ static void atkbd_cleanup(struct serio *serio)
static void atkbd_disconnect(struct serio *serio)
{
struct atkbd *atkbd = serio->private;
clear_bit(ATKBD_FLAG_ENABLED, &atkbd->flags);
input_unregister_device(&atkbd->dev);
serio_close(serio);
kfree(atkbd);
......@@ -709,17 +757,22 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
return;
}
if (!atkbd->write)
atkbd_softrepeat = 1;
if (atkbd_softrepeat)
atkbd_softraw = 1;
if (atkbd->write) {
atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP) | BIT(EV_MSC);
atkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
} else atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
} else atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_MSC);
atkbd->dev.mscbit[0] = atkbd_softraw ? BIT(MSC_SCAN) : BIT(MSC_RAW) | BIT(MSC_SCAN);
if (!atkbd_softrepeat) {
atkbd->dev.rep[REP_DELAY] = 250;
atkbd->dev.rep[REP_PERIOD] = 33;
}
} else atkbd_softraw = 1;
atkbd->ack = 1;
atkbd->serio = serio;
init_input_dev(&atkbd->dev);
......@@ -754,8 +807,6 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
atkbd->id = 0xab00;
}
atkbd->enabled = 1;
if (atkbd->extra) {
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");
......@@ -797,6 +848,8 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
input_register_device(&atkbd->dev);
set_bit(ATKBD_FLAG_ENABLED, &atkbd->flags);
printk(KERN_INFO "input: %s on %s\n", atkbd->name, serio->phys);
}
......@@ -832,6 +885,8 @@ static int atkbd_reconnect(struct serio *serio)
return -1;
}
set_bit(ATKBD_FLAG_ENABLED, &atkbd->flags);
return 0;
}
......
......@@ -279,6 +279,9 @@ static unsigned int uinput_poll(struct file *file, poll_table *wait)
{
struct uinput_device *udev = file->private_data;
if (!test_bit(UIST_CREATED, &(udev->state)))
return 0;
poll_wait(file, &udev->waitq, wait);
if (udev->head != udev->tail)
......
......@@ -30,8 +30,6 @@ config MOUSE_PS2
and a new verion of GPM at:
http://www.geocities.com/dt_or/gpm/gpm.html
to take advantage of the advanced features of the touchpad.
If you do not want install specialized drivers but want tapping
working please use option psmouse.proto=imps.
If unsure, say Y.
......
......@@ -277,7 +277,7 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties)
protocol = PSMOUSE_PS2TPP;
}
} else if (get_model_info(model) != NULL) {
} else if (model_info != NULL) {
param[0] = param[1] = param[2] = 0;
ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */
......
......@@ -142,34 +142,45 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
printk(KERN_WARNING "psmouse.c: bad data from KBC -%s%s\n",
flags & SERIO_TIMEOUT ? " timeout" : "",
flags & SERIO_PARITY ? " bad parity" : "");
if (psmouse->acking) {
psmouse->ack = -1;
psmouse->acking = 0;
}
psmouse->pktcnt = 0;
psmouse->nak = 1;
clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
goto out;
}
if (psmouse->acking) {
if (test_bit(PSMOUSE_FLAG_ACK, &psmouse->flags))
switch (data) {
case PSMOUSE_RET_ACK:
psmouse->ack = 1;
psmouse->nak = 0;
clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
goto out;
break;
case PSMOUSE_RET_NAK:
psmouse->ack = -1;
break;
psmouse->nak = 1;
clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
goto out;
default:
psmouse->ack = 1; /* Workaround for mice which don't ACK the Get ID command */
if (psmouse->cmdcnt)
psmouse->cmdbuf[--psmouse->cmdcnt] = data;
break;
psmouse->nak = 0; /* Workaround for mice which don't ACK the Get ID command */
clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
if (!test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags))
goto out;
}
psmouse->acking = 0;
goto out;
}
if (psmouse->cmdcnt) {
psmouse->cmdbuf[--psmouse->cmdcnt] = data;
if (test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags)) {
psmouse->cmdcnt--;
psmouse->cmdbuf[psmouse->cmdcnt] = data;
if (psmouse->cmdcnt == 1) {
if (data != 0xab && data != 0xac)
clear_bit(PSMOUSE_FLAG_ID, &psmouse->flags);
clear_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags);
}
if (!psmouse->cmdcnt)
clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
goto out;
}
......@@ -242,18 +253,15 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
static int psmouse_sendbyte(struct psmouse *psmouse, unsigned char byte)
{
int timeout = 10000; /* 100 msec */
psmouse->ack = 0;
psmouse->acking = 1;
int timeout = 200000; /* 200 msec */
if (serio_write(psmouse->serio, byte)) {
psmouse->acking = 0;
set_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
if (serio_write(psmouse->serio, byte))
return -1;
}
while (!psmouse->ack && timeout--) udelay(10);
while (test_bit(PSMOUSE_FLAG_ACK, &psmouse->flags) && timeout--) udelay(1);
clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
return -(psmouse->ack <= 0);
return -psmouse->nak;
}
/*
......@@ -271,46 +279,62 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command)
psmouse->cmdcnt = receive;
if (command == PSMOUSE_CMD_RESET_BAT)
timeout = 4000000; /* 4 sec */
timeout = 4000000; /* 4 sec */
/* initialize cmdbuf with preset values from param */
if (receive)
for (i = 0; i < receive; i++)
psmouse->cmdbuf[(receive - 1) - i] = param[i];
if (receive && param)
for (i = 0; i < receive; i++)
psmouse->cmdbuf[(receive - 1) - i] = param[i];
if (receive) {
set_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
set_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags);
set_bit(PSMOUSE_FLAG_ID, &psmouse->flags);
}
if (command & 0xff)
if (psmouse_sendbyte(psmouse, command & 0xff))
return (psmouse->cmdcnt = 0) - 1;
if (psmouse_sendbyte(psmouse, command & 0xff)) {
clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
return -1;
}
for (i = 0; i < send; i++)
if (psmouse_sendbyte(psmouse, param[i]))
return (psmouse->cmdcnt = 0) - 1;
if (psmouse_sendbyte(psmouse, param[i])) {
clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
return -1;
}
while (psmouse->cmdcnt && timeout--) {
while (test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags) && timeout--) {
if (psmouse->cmdcnt == 1 && command == PSMOUSE_CMD_RESET_BAT &&
timeout > 100000) /* do not run in a endless loop */
timeout = 100000; /* 1 sec */
if (!test_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags)) {
if (command == PSMOUSE_CMD_RESET_BAT && timeout > 100000)
timeout = 100000;
if (psmouse->cmdcnt == 1 && command == PSMOUSE_CMD_GETID &&
psmouse->cmdbuf[1] != 0xab && psmouse->cmdbuf[1] != 0xac) {
psmouse->cmdcnt = 0;
break;
if (command == PSMOUSE_CMD_GETID && !test_bit(PSMOUSE_FLAG_ID, &psmouse->flags)) {
clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
psmouse->cmdcnt = 0;
break;
}
}
udelay(1);
}
for (i = 0; i < receive; i++)
param[i] = psmouse->cmdbuf[(receive - 1) - i];
clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
if (param)
for (i = 0; i < receive; i++)
param[i] = psmouse->cmdbuf[(receive - 1) - i];
if (command == PSMOUSE_CMD_RESET_BAT && psmouse->cmdcnt == 1)
return 0;
if (psmouse->cmdcnt)
return (psmouse->cmdcnt = 0) - 1;
return -1;
return 0;
}
/*
* psmouse_sliced_command() sends an extended PS/2 command to the mouse
* using sliced syntax, understood by advanced devices, such as Logitech
......@@ -735,7 +759,12 @@ static int psmouse_reconnect(struct serio *serio)
}
psmouse->state = PSMOUSE_CMD_MODE;
psmouse->acking = psmouse->cmdcnt = psmouse->pktcnt = psmouse->out_of_sync = 0;
clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
psmouse->pktcnt = psmouse->out_of_sync = 0;
if (psmouse->reconnect) {
if (psmouse->reconnect(psmouse))
return -1;
......
......@@ -22,6 +22,11 @@
#define PSMOUSE_ACTIVATED 1
#define PSMOUSE_IGNORE 2
#define PSMOUSE_FLAG_ACK 0 /* Waiting for ACK/NAK */
#define PSMOUSE_FLAG_CMD 1 /* Waiting for command to finish */
#define PSMOUSE_FLAG_CMD1 2 /* First byte of command response */
#define PSMOUSE_FLAG_ID 3 /* First byte is not keyboard ID */
/* psmouse protocol handler return codes */
typedef enum {
PSMOUSE_BAD_DATA,
......@@ -54,11 +59,11 @@ struct psmouse {
unsigned long last;
unsigned long out_of_sync;
unsigned char state;
char acking;
volatile char ack;
unsigned char nak;
char error;
char devname[64];
char phys[32];
unsigned long flags;
psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs);
int (*reconnect)(struct psmouse *psmouse);
......
......@@ -48,8 +48,13 @@ static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y;
module_param(yres, uint, 0);
MODULE_PARM_DESC(yres, "Vertical screen resolution");
static unsigned tap_time = 200;
module_param(tap_time, uint, 0);
MODULE_PARM_DESC(tap_time, "Tap time for touchpads in absolute mode (msecs)");
struct mousedev_motion {
int dx, dy, dz;
unsigned long buttons;
};
struct mousedev {
......@@ -62,21 +67,31 @@ struct mousedev {
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;
unsigned long touch;
};
enum mousedev_emul {
MOUSEDEV_EMUL_PS2,
MOUSEDEV_EMUL_IMPS,
MOUSEDEV_EMUL_EXPS
} __attribute__ ((packed));
#define PACKET_QUEUE_LEN 16
struct mousedev_list {
struct fasync_struct *fasync;
struct mousedev *mousedev;
struct list_head node;
int dx, dy, dz;
unsigned long buttons;
struct mousedev_motion packets[PACKET_QUEUE_LEN];
unsigned int head, tail;
spinlock_t packet_lock;
signed char ps2[6];
unsigned char ready, buffer, bufsiz;
unsigned char mode, imexseq, impsseq;
unsigned char imexseq, impsseq;
enum mousedev_emul mode;
};
#define MOUSEDEV_SEQ_LEN 6
......@@ -165,30 +180,70 @@ static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int
}
if (value) {
set_bit(index, &mousedev->buttons);
set_bit(index, &mousedev_mix.buttons);
set_bit(index, &mousedev->packet.buttons);
set_bit(index, &mousedev_mix.packet.buttons);
} else {
clear_bit(index, &mousedev->buttons);
clear_bit(index, &mousedev_mix.buttons);
clear_bit(index, &mousedev->packet.buttons);
clear_bit(index, &mousedev_mix.packet.buttons);
}
}
static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_motion *packet)
{
struct mousedev_list *list;
struct mousedev_motion *p;
unsigned long flags;
list_for_each_entry(list, &mousedev->list, node) {
list->dx += packet->dx;
list->dy += packet->dy;
list->dz += packet->dz;
list->buttons = mousedev->buttons;
spin_lock_irqsave(&list->packet_lock, flags);
p = &list->packets[list->head];
if (list->ready && p->buttons != packet->buttons) {
unsigned int new_head = (list->head + 1) % PACKET_QUEUE_LEN;
if (new_head != list->tail) {
p = &list->packets[list->head = new_head];
memset(p, 0, sizeof(struct mousedev_motion));
}
}
p->dx += packet->dx;
p->dy += packet->dy;
p->dz += packet->dz;
p->buttons = mousedev->packet.buttons;
list->ready = 1;
spin_unlock_irqrestore(&list->packet_lock, flags);
kill_fasync(&list->fasync, SIGIO, POLL_IN);
}
wake_up_interruptible(&mousedev->wait);
}
static void mousedev_touchpad_touch(struct mousedev *mousedev, int value)
{
if (!value) {
if (mousedev->touch &&
!time_after(jiffies, mousedev->touch + msecs_to_jiffies(tap_time))) {
/*
* Toggle left button to emulate tap.
* We rely on the fact that mousedev_mix always has 0
* motion packet so we won't mess current position.
*/
set_bit(0, &mousedev->packet.buttons);
set_bit(0, &mousedev_mix.packet.buttons);
mousedev_notify_readers(mousedev, &mousedev_mix.packet);
mousedev_notify_readers(&mousedev_mix, &mousedev_mix.packet);
clear_bit(0, &mousedev->packet.buttons);
clear_bit(0, &mousedev_mix.packet.buttons);
}
mousedev->touch = mousedev->pkt_count = 0;
}
else
if (!mousedev->touch)
mousedev->touch = jiffies;
}
static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
struct mousedev *mousedev = handle->private;
......@@ -212,12 +267,8 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig
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;
}
if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
mousedev_touchpad_touch(mousedev, value);
else
mousedev_key_event(mousedev, code, value);
}
......@@ -237,7 +288,7 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig
mousedev_notify_readers(mousedev, &mousedev->packet);
mousedev_notify_readers(&mousedev_mix, &mousedev->packet);
memset(&mousedev->packet, 0, sizeof(struct mousedev_motion));
mousedev->packet.dx = mousedev->packet.dy = mousedev->packet.dz = 0;
}
break;
}
......@@ -322,6 +373,7 @@ static int mousedev_open(struct inode * inode, struct file * file)
return -ENOMEM;
memset(list, 0, sizeof(struct mousedev_list));
spin_lock_init(&list->packet_lock);
list->mousedev = mousedev_table[i];
list_add_tail(&list->node, &mousedev_table[i]->list);
file->private_data = list;
......@@ -341,32 +393,56 @@ static int mousedev_open(struct inode * inode, struct file * file)
return 0;
}
static void mousedev_packet(struct mousedev_list *list, unsigned char off)
static inline int mousedev_limit_delta(int delta, int limit)
{
list->ps2[off] = 0x08 | ((list->dx < 0) << 4) | ((list->dy < 0) << 5) | (list->buttons & 0x07);
list->ps2[off + 1] = (list->dx > 127 ? 127 : (list->dx < -127 ? -127 : list->dx));
list->ps2[off + 2] = (list->dy > 127 ? 127 : (list->dy < -127 ? -127 : list->dy));
list->dx -= list->ps2[off + 1];
list->dy -= list->ps2[off + 2];
list->bufsiz = off + 3;
if (list->mode == 2) {
list->ps2[off + 3] = (list->dz > 7 ? 7 : (list->dz < -7 ? -7 : list->dz));
list->dz -= list->ps2[off + 3];
list->ps2[off + 3] = (list->ps2[off + 3] & 0x0f) | ((list->buttons & 0x18) << 1);
list->bufsiz++;
} else {
list->ps2[off] |= ((list->buttons & 0x10) >> 3) | ((list->buttons & 0x08) >> 1);
return delta > limit ? limit : (delta < -limit ? -limit : delta);
}
static void mousedev_packet(struct mousedev_list *list, signed char *ps2_data)
{
struct mousedev_motion *p;
unsigned long flags;
spin_lock_irqsave(&list->packet_lock, flags);
p = &list->packets[list->tail];
ps2_data[0] = 0x08 | ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07);
ps2_data[1] = mousedev_limit_delta(p->dx, 127);
ps2_data[2] = mousedev_limit_delta(p->dy, 127);
p->dx -= ps2_data[1];
p->dy -= ps2_data[2];
switch (list->mode) {
case MOUSEDEV_EMUL_EXPS:
ps2_data[3] = mousedev_limit_delta(p->dz, 127);
p->dz -= ps2_data[3];
ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1);
list->bufsiz = 4;
break;
case MOUSEDEV_EMUL_IMPS:
ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
ps2_data[3] = mousedev_limit_delta(p->dz, 127);
p->dz -= ps2_data[3];
list->bufsiz = 4;
break;
case MOUSEDEV_EMUL_PS2:
default:
ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
p->dz = 0;
list->bufsiz = 3;
break;
}
if (list->mode == 1) {
list->ps2[off + 3] = (list->dz > 127 ? 127 : (list->dz < -127 ? -127 : list->dz));
list->dz -= list->ps2[off + 3];
list->bufsiz++;
if (!p->dx && !p->dy && !p->dz) {
if (list->tail != list->head)
list->tail = (list->tail + 1) % PACKET_QUEUE_LEN;
if (list->tail == list->head)
list->ready = 0;
}
if (!list->dx && !list->dy && (!list->mode || !list->dz)) list->ready = 0;
list->buffer = list->bufsiz;
spin_unlock_irqrestore(&list->packet_lock, flags);
}
......@@ -384,31 +460,31 @@ static ssize_t mousedev_write(struct file * file, const char __user * buffer, si
if (c == mousedev_imex_seq[list->imexseq]) {
if (++list->imexseq == MOUSEDEV_SEQ_LEN) {
list->imexseq = 0;
list->mode = 2;
list->mode = MOUSEDEV_EMUL_EXPS;
}
} else list->imexseq = 0;
if (c == mousedev_imps_seq[list->impsseq]) {
if (++list->impsseq == MOUSEDEV_SEQ_LEN) {
list->impsseq = 0;
list->mode = 1;
list->mode = MOUSEDEV_EMUL_IMPS;
}
} else list->impsseq = 0;
list->ps2[0] = 0xfa;
list->bufsiz = 1;
switch (c) {
case 0xeb: /* Poll */
mousedev_packet(list, 1);
mousedev_packet(list, &list->ps2[1]);
list->bufsiz++; /* account for leading ACK */
break;
case 0xf2: /* Get ID */
switch (list->mode) {
case 0: list->ps2[1] = 0; break;
case 1: list->ps2[1] = 3; break;
case 2: list->ps2[1] = 4; break;
case MOUSEDEV_EMUL_PS2: list->ps2[1] = 0; break;
case MOUSEDEV_EMUL_IMPS: list->ps2[1] = 3; break;
case MOUSEDEV_EMUL_EXPS: list->ps2[1] = 4; break;
}
list->bufsiz = 2;
break;
......@@ -419,13 +495,15 @@ static ssize_t mousedev_write(struct file * file, const char __user * buffer, si
break;
case 0xff: /* Reset */
list->impsseq = 0;
list->imexseq = 0;
list->mode = 0;
list->ps2[1] = 0xaa;
list->ps2[2] = 0x00;
list->impsseq = list->imexseq = 0;
list->mode = MOUSEDEV_EMUL_PS2;
list->ps2[1] = 0xaa; list->ps2[2] = 0x00;
list->bufsiz = 3;
break;
default:
list->bufsiz = 1;
break;
}
list->buffer = list->bufsiz;
......@@ -451,8 +529,10 @@ static ssize_t mousedev_read(struct file * file, char __user * buffer, size_t co
if (retval)
return retval;
if (!list->buffer && list->ready)
mousedev_packet(list, 0);
if (!list->buffer && list->ready) {
mousedev_packet(list, list->ps2);
list->buffer = list->bufsiz;
}
if (count > list->buffer)
count = list->buffer;
......
/*
* i8042 keyboard and mouse controller driver for Linux
*
* Copyright (c) 1999-2002 Vojtech Pavlik
* Copyright (c) 1999-2004 Vojtech Pavlik
*/
/*
......@@ -52,6 +52,10 @@ static unsigned int i8042_dumbkbd;
module_param_named(dumbkbd, i8042_dumbkbd, bool, 0);
MODULE_PARM_DESC(dumbkbd, "Pretend that controller can only read data from keyboard");
extern unsigned int i8042_dmi_noloop;
static unsigned int i8042_noloop;
extern unsigned int i8042_dmi_noloop;
__obsolete_setup("i8042_noaux");
__obsolete_setup("i8042_nomux");
__obsolete_setup("i8042_unlock");
......@@ -95,6 +99,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs);
/*
* The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to
* be ready for reading values from it / writing values to it.
* Called always with i8042_lock held.
*/
static int i8042_wait_read(void)
......@@ -154,6 +159,9 @@ static int i8042_command(unsigned char *param, int command)
unsigned long flags;
int retval = 0, i = 0;
if (i8042_noloop && command == I8042_CMD_AUX_LOOP)
return -1;
spin_lock_irqsave(&i8042_lock, flags);
retval = i8042_wait_write();
......@@ -474,17 +482,8 @@ static int i8042_enable_mux_mode(struct i8042_values *values, unsigned char *mux
if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0xa9)
return -1;
param = 0xa4;
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);
if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param == 0x5b)
return -1;
}
if (mux_version)
*mux_version = ~param;
......@@ -677,6 +676,7 @@ static void i8042_timer_func(unsigned long data)
static int i8042_controller_init(void)
{
unsigned long flags;
/*
* Test the i8042. We need to know if it thinks it's working correctly
......@@ -723,12 +723,14 @@ static int i8042_controller_init(void)
* Handle keylock.
*/
spin_lock_irqsave(&i8042_lock, flags);
if (~i8042_read_status() & I8042_STR_KEYLOCK) {
if (i8042_unlock)
i8042_ctr |= I8042_CTR_IGNKEYLOCK;
else
printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n");
}
spin_unlock_irqrestore(&i8042_lock, flags);
/*
* If the chip is configured into nontranslated mode by the BIOS, don't
......@@ -964,6 +966,13 @@ int __init i8042_init(void)
if (i8042_dumbkbd)
i8042_kbd_port.write = NULL;
#ifdef __i386__
if (i8042_dmi_noloop) {
printk(KERN_INFO "i8042.c: AUX LoopBack command disabled by DMI.\n");
i8042_noloop = 1;
}
#endif
if (!i8042_noaux && !i8042_check_aux(&i8042_aux_values)) {
if (!i8042_nomux && !i8042_check_mux(&i8042_aux_values))
for (i = 0; i < 4; i++) {
......
......@@ -67,12 +67,18 @@ struct serio_event {
struct list_head node;
};
static DECLARE_MUTEX(serio_sem);
static spinlock_t serio_event_lock = SPIN_LOCK_UNLOCKED; /* protects serio_event_list */
static DECLARE_MUTEX(serio_sem); /* protects serio_list and serio_dev_list */
static LIST_HEAD(serio_list);
static LIST_HEAD(serio_dev_list);
static LIST_HEAD(serio_event_list);
static int serio_pid;
/*
* serio_find_dev() must be called with serio_sem down.
*/
static void serio_find_dev(struct serio *serio)
{
struct serio_dev *dev;
......@@ -93,26 +99,48 @@ static void serio_find_dev(struct serio *serio)
static DECLARE_WAIT_QUEUE_HEAD(serio_wait);
static DECLARE_COMPLETION(serio_exited);
static void serio_invalidate_pending_events(struct serio *serio)
static void serio_remove_pending_events(struct serio *serio)
{
struct list_head *node, *next;
struct serio_event *event;
unsigned long flags;
spin_lock_irqsave(&serio_event_lock, flags);
list_for_each_entry(event, &serio_event_list, node)
if (event->serio == serio)
event->serio = NULL;
list_for_each_safe(node, next, &serio_event_list) {
event = container_of(node, struct serio_event, node);
if (event->serio == serio) {
list_del_init(node);
kfree(event);
}
}
spin_unlock_irqrestore(&serio_event_lock, flags);
}
void serio_handle_events(void)
{
struct list_head *node, *next;
struct list_head *node;
struct serio_event *event;
unsigned long flags;
list_for_each_safe(node, next, &serio_event_list) {
while (1) {
spin_lock_irqsave(&serio_event_lock, flags);
if (list_empty(&serio_event_list)) {
spin_unlock_irqrestore(&serio_event_lock, flags);
break;
}
node = serio_event_list.next;
event = container_of(node, struct serio_event, node);
list_del_init(node);
spin_unlock_irqrestore(&serio_event_lock, flags);
down(&serio_sem);
if (event->serio == NULL)
goto event_done;
switch (event->type) {
case SERIO_REGISTER_PORT :
......@@ -137,9 +165,8 @@ void serio_handle_events(void)
default:
break;
}
event_done:
up(&serio_sem);
list_del_init(node);
kfree(event);
}
}
......@@ -165,8 +192,11 @@ static int serio_thread(void *nothing)
static void serio_queue_event(struct serio *serio, int event_type)
{
unsigned long flags;
struct serio_event *event;
spin_lock_irqsave(&serio_event_lock, flags);
if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) {
event->type = event_type;
event->serio = serio;
......@@ -174,6 +204,8 @@ static void serio_queue_event(struct serio *serio, int event_type)
list_add_tail(&event->node, &serio_event_list);
wake_up(&serio_wait);
}
spin_unlock_irqrestore(&serio_event_lock, flags);
}
void serio_rescan(struct serio *serio)
......@@ -187,21 +219,27 @@ void serio_reconnect(struct serio *serio)
}
irqreturn_t serio_interrupt(struct serio *serio,
unsigned char data, unsigned int flags, struct pt_regs *regs)
unsigned char data, unsigned int dfl, struct pt_regs *regs)
{
unsigned long flags;
irqreturn_t ret = IRQ_NONE;
if (serio->dev && serio->dev->interrupt) {
ret = serio->dev->interrupt(serio, data, flags, regs);
spin_lock_irqsave(&serio->lock, flags);
if (likely(serio->dev)) {
ret = serio->dev->interrupt(serio, data, dfl, regs);
} else {
if (!flags) {
if ((serio->type == SERIO_8042 ||
serio->type == SERIO_8042_XL) && (data != 0xaa))
return ret;
serio_rescan(serio);
ret = IRQ_HANDLED;
if (!dfl) {
if ((serio->type != SERIO_8042 &&
serio->type != SERIO_8042_XL) || (data == 0xaa)) {
serio_rescan(serio);
ret = IRQ_HANDLED;
}
}
}
spin_unlock_irqrestore(&serio->lock, flags);
return ret;
}
......@@ -229,6 +267,7 @@ void serio_register_port_delayed(struct serio *serio)
*/
void __serio_register_port(struct serio *serio)
{
spin_lock_init(&serio->lock);
list_add_tail(&serio->node, &serio_list);
serio_find_dev(serio);
}
......@@ -257,7 +296,7 @@ void serio_unregister_port_delayed(struct serio *serio)
*/
void __serio_unregister_port(struct serio *serio)
{
serio_invalidate_pending_events(serio);
serio_remove_pending_events(serio);
list_del_init(&serio->node);
if (serio->dev && serio->dev->disconnect)
serio->dev->disconnect(serio);
......@@ -292,9 +331,15 @@ 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)
{
unsigned long flags;
spin_lock_irqsave(&serio->lock, flags);
serio->dev = dev;
spin_unlock_irqrestore(&serio->lock, flags);
if (serio->open && serio->open(serio)) {
spin_lock_irqsave(&serio->lock, flags);
serio->dev = NULL;
spin_unlock_irqrestore(&serio->lock, flags);
return -1;
}
return 0;
......@@ -303,9 +348,13 @@ int serio_open(struct serio *serio, struct serio_dev *dev)
/* called from serio_dev->connect/disconnect methods under serio_sem */
void serio_close(struct serio *serio)
{
unsigned long flags;
if (serio->close)
serio->close(serio);
spin_lock_irqsave(&serio->lock, flags);
serio->dev = NULL;
spin_unlock_irqrestore(&serio->lock, flags);
}
static int __init serio_init(void)
......
......@@ -3,9 +3,17 @@
*
* Copyright (c) 2001 "Crazy" james Simmons
*
* Input driver to Touchscreen device driver module.
* Compaq touchscreen protocol driver. The protocol emulated by this driver
* is obsolete; for new programs use the tslib library which can read directly
* from evdev and perform dejittering, variance filtering and calibration -
* all in user space, not at kernel level. The meaning of this driver is
* to allow usage of newer input drivers with old applications that use the
* old /dev/h3600_ts and /dev/h3600_tsraw devices.
*
* Sponsored by Transvirtual Technology
* 09-Apr-2004: Andrew Zabolotny <zap@homelink.ru>
* Fixed to actually work, not just output random numbers.
* Added support for both h3600_ts and h3600_tsraw protocol
* emulation.
*/
/*
......@@ -24,11 +32,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <jsimmons@transvirtual.com>.
* e-mail - mail your message to <jsimmons@infradead.org>.
*/
#define TSDEV_MINOR_BASE 128
#define TSDEV_MINORS 32
/* First 16 devices are h3600_ts compatible; second 16 are h3600_tsraw */
#define TSDEV_MINOR_MASK 15
#define TSDEV_BUFFER_SIZE 64
#include <linux/slab.h>
......@@ -52,48 +62,84 @@
#define CONFIG_INPUT_TSDEV_SCREEN_Y 320
#endif
/* This driver emulates both protocols of the old h3600_ts and h3600_tsraw
* devices. The first one must output X/Y data in 'cooked' format, e.g.
* filtered, dejittered and calibrated. Second device just outputs raw
* data received from the hardware.
*
* This driver doesn't support filtering and dejittering; it supports only
* calibration. Filtering and dejittering must be done in the low-level
* driver, if needed, because it may gain additional benefits from knowing
* the low-level details, the nature of noise and so on.
*
* The driver precomputes a calibration matrix given the initial xres and
* yres values (quite innacurate for most touchscreens) that will result
* in a more or less expected range of output values. The driver supports
* the TS_SET_CAL ioctl, which will replace the calibration matrix with a
* new one, supposedly generated from the values taken from the raw device.
*/
MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
MODULE_DESCRIPTION("Input driver to touchscreen converter");
MODULE_LICENSE("GPL");
static int xres = CONFIG_INPUT_TSDEV_SCREEN_X;
module_param(xres, uint, 0);
MODULE_PARM_DESC(xres, "Horizontal screen resolution");
MODULE_PARM_DESC(xres, "Horizontal screen resolution (can be negative for X-mirror)");
static int yres = CONFIG_INPUT_TSDEV_SCREEN_Y;
module_param(yres, uint, 0);
MODULE_PARM_DESC(yres, "Vertical screen resolution");
MODULE_PARM_DESC(yres, "Vertical screen resolution (can be negative for Y-mirror)");
/* From Compaq's Touch Screen Specification version 0.2 (draft) */
struct ts_event {
short pressure;
short x;
short y;
short millisecs;
};
struct ts_calibration {
int xscale;
int xtrans;
int yscale;
int ytrans;
int xyswap;
};
struct tsdev {
int exist;
int open;
int minor;
char name[16];
char name[8];
wait_queue_head_t wait;
struct list_head list;
struct input_handle handle;
int x, y, pressure;
struct ts_calibration cal;
};
/* From Compaq's Touch Screen Specification version 0.2 (draft) */
typedef struct {
short pressure;
short x;
short y;
short millisecs;
} TS_EVENT;
struct tsdev_list {
struct fasync_struct *fasync;
struct list_head node;
struct tsdev *tsdev;
int head, tail;
int oldx, oldy, pendown;
TS_EVENT event[TSDEV_BUFFER_SIZE];
struct ts_event event[TSDEV_BUFFER_SIZE];
int raw;
};
/* The following ioctl codes are defined ONLY for backward compatibility.
* Don't use tsdev for new developement; use the tslib library instead.
* Touchscreen calibration is a fully userspace task.
*/
/* Use 'f' as magic number */
#define IOC_H3600_TS_MAGIC 'f'
#define TS_GET_CAL _IOR(IOC_H3600_TS_MAGIC, 10, struct ts_calibration)
#define TS_SET_CAL _IOW(IOC_H3600_TS_MAGIC, 11, struct ts_calibration)
static struct input_handler tsdev_handler;
static struct tsdev *tsdev_table[TSDEV_MINORS];
static struct tsdev *tsdev_table[TSDEV_MINORS/2];
static int tsdev_fasync(int fd, struct file *file, int on)
{
......@@ -109,13 +155,16 @@ static int tsdev_open(struct inode *inode, struct file *file)
int i = iminor(inode) - TSDEV_MINOR_BASE;
struct tsdev_list *list;
if (i >= TSDEV_MINORS || !tsdev_table[i])
if (i >= TSDEV_MINORS || !tsdev_table[i & TSDEV_MINOR_MASK])
return -ENODEV;
if (!(list = kmalloc(sizeof(struct tsdev_list), GFP_KERNEL)))
return -ENOMEM;
memset(list, 0, sizeof(struct tsdev_list));
list->raw = (i >= TSDEV_MINORS/2) ? 1 : 0;
i &= TSDEV_MINOR_MASK;
list->tsdev = tsdev_table[i];
list_add_tail(&list->node, &tsdev_table[i]->list);
file->private_data = list;
......@@ -169,11 +218,13 @@ static ssize_t tsdev_read(struct file *file, char *buffer, size_t count,
if (!list->tsdev->exist)
return -ENODEV;
while (list->head != list->tail && retval + sizeof(TS_EVENT) <= count) {
if (copy_to_user (buffer + retval, list->event + list->tail, sizeof(TS_EVENT)))
while (list->head != list->tail &&
retval + sizeof (struct ts_event) <= count) {
if (copy_to_user (buffer + retval, list->event + list->tail,
sizeof (struct ts_event)))
return -EFAULT;
list->tail = (list->tail + 1) & (TSDEV_BUFFER_SIZE - 1);
retval += sizeof(TS_EVENT);
retval += sizeof (struct ts_event);
}
return retval;
......@@ -193,22 +244,27 @@ static unsigned int tsdev_poll(struct file *file, poll_table * wait)
static int tsdev_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
/*
struct tsdev_list *list = file->private_data;
struct tsdev *evdev = list->tsdev;
struct input_dev *dev = tsdev->handle.dev;
int retval;
struct tsdev *tsdev = list->tsdev;
int retval = 0;
switch (cmd) {
case HHEHE:
return 0;
case hjff:
return 0;
default:
return 0;
case TS_GET_CAL:
if (copy_to_user ((void *)arg, &tsdev->cal,
sizeof (struct ts_calibration)))
retval = -EFAULT;
break;
case TS_SET_CAL:
if (copy_from_user (&tsdev->cal, (void *)arg,
sizeof (struct ts_calibration)))
retval = -EFAULT;
break;
default:
retval = -EINVAL;
break;
}
*/
return -EINVAL;
return retval;
}
struct file_operations tsdev_fops = {
......@@ -227,82 +283,85 @@ static void tsdev_event(struct input_handle *handle, unsigned int type,
struct tsdev *tsdev = handle->private;
struct tsdev_list *list;
struct timeval time;
int size;
list_for_each_entry(list, &tsdev->list, node) {
switch (type) {
case EV_ABS:
switch (code) {
case ABS_X:
if (!list->pendown)
return;
size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X];
if (size > 0)
list->oldx = ((value - handle->dev->absmin[ABS_X]) * xres / size);
else
list->oldx = ((value - handle->dev->absmin[ABS_X]));
break;
case ABS_Y:
if (!list->pendown)
return;
size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y];
if (size > 0)
list->oldy = ((value - handle->dev->absmin[ABS_Y]) * yres / size);
else
list->oldy = ((value - handle->dev->absmin[ABS_Y]));
break;
case ABS_PRESSURE:
list->pendown = ((value > handle->dev-> absmin[ABS_PRESSURE])) ?
value - handle->dev->absmin[ABS_PRESSURE] : 0;
break;
}
switch (type) {
case EV_ABS:
switch (code) {
case ABS_X:
tsdev->x = value;
break;
case ABS_Y:
tsdev->y = value;
break;
case ABS_PRESSURE:
if (value > handle->dev->absmax[ABS_PRESSURE])
value = handle->dev->absmax[ABS_PRESSURE];
value -= handle->dev->absmin[ABS_PRESSURE];
if (value < 0)
value = 0;
tsdev->pressure = value;
break;
}
break;
case EV_REL:
switch (code) {
case REL_X:
tsdev->x += value;
if (tsdev->x < 0)
tsdev->x = 0;
else if (tsdev->x > xres)
tsdev->x = xres;
break;
case REL_Y:
tsdev->y += value;
if (tsdev->y < 0)
tsdev->y = 0;
else if (tsdev->y > yres)
tsdev->y = yres;
break;
}
break;
case EV_REL:
switch (code) {
case REL_X:
if (!list->pendown)
return;
list->oldx += value;
if (list->oldx < 0)
list->oldx = 0;
else if (list->oldx > xres)
list->oldx = xres;
case EV_KEY:
if (code == BTN_TOUCH || code == BTN_MOUSE) {
switch (value) {
case 0:
tsdev->pressure = 0;
break;
case REL_Y:
if (!list->pendown)
return;
list->oldy += value;
if (list->oldy < 0)
list->oldy = 0;
else if (list->oldy > xres)
list->oldy = xres;
case 1:
if (!tsdev->pressure)
tsdev->pressure = 1;
break;
}
break;
case EV_KEY:
if (code == BTN_TOUCH || code == BTN_MOUSE) {
switch (value) {
case 0:
list->pendown = 0;
break;
case 1:
if (!list->pendown)
list->pendown = 1;
break;
case 2:
return;
}
} else
return;
break;
}
break;
}
if (type != EV_SYN || code != SYN_REPORT)
return;
list_for_each_entry(list, &tsdev->list, node) {
int x, y, tmp;
do_gettimeofday(&time);
list->event[list->head].millisecs = time.tv_usec / 100;
list->event[list->head].pressure = list->pendown;
list->event[list->head].x = list->oldx;
list->event[list->head].y = list->oldy;
list->event[list->head].pressure = tsdev->pressure;
x = tsdev->x;
y = tsdev->y;
/* Calibration */
if (!list->raw) {
x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans;
y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans;
if (tsdev->cal.xyswap) {
tmp = x; x = y; y = tmp;
}
}
list->event[list->head].x = x;
list->event[list->head].y = y;
list->head = (list->head + 1) & (TSDEV_BUFFER_SIZE - 1);
kill_fasync(&list->fasync, SIGIO, POLL_IN);
}
......@@ -314,11 +373,11 @@ static struct input_handle *tsdev_connect(struct input_handler *handler,
struct input_device_id *id)
{
struct tsdev *tsdev;
int minor;
int minor, delta;
for (minor = 0; minor < TSDEV_MINORS && tsdev_table[minor];
for (minor = 0; minor < TSDEV_MINORS/2 && tsdev_table[minor];
minor++);
if (minor == TSDEV_MINORS) {
if (minor >= TSDEV_MINORS/2) {
printk(KERN_ERR
"tsdev: You have way too many touchscreens\n");
return NULL;
......@@ -340,10 +399,25 @@ static struct input_handle *tsdev_connect(struct input_handler *handler,
tsdev->handle.handler = handler;
tsdev->handle.private = tsdev;
/* Precompute the rough calibration matrix */
delta = dev->absmax [ABS_X] - dev->absmin [ABS_X] + 1;
if (delta == 0)
delta = 1;
tsdev->cal.xscale = (xres << 8) / delta;
tsdev->cal.xtrans = - ((dev->absmin [ABS_X] * tsdev->cal.xscale) >> 8);
delta = dev->absmax [ABS_Y] - dev->absmin [ABS_Y] + 1;
if (delta == 0)
delta = 1;
tsdev->cal.yscale = (yres << 8) / delta;
tsdev->cal.ytrans = - ((dev->absmin [ABS_Y] * tsdev->cal.yscale) >> 8);
tsdev_table[minor] = tsdev;
devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor),
S_IFCHR|S_IRUGO|S_IWUSR, "input/ts%d", minor);
devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor + TSDEV_MINORS/2),
S_IFCHR|S_IRUGO|S_IWUSR, "input/tsraw%d", minor);
class_simple_device_add(input_class,
MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor),
dev->dev, "ts%d", minor);
......@@ -362,6 +436,7 @@ static void tsdev_disconnect(struct input_handle *handle)
wake_up_interruptible(&tsdev->wait);
} else
tsdev_free(tsdev);
devfs_remove("input/tsraw%d", tsdev->minor);
}
static struct input_device_id tsdev_ids[] = {
......@@ -379,6 +454,12 @@ static struct input_device_id tsdev_ids[] = {
.absbit = { BIT(ABS_X) | BIT(ABS_Y) },
},/* A tablet like device, at least touch detection, two absolute axes */
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
.evbit = { BIT(EV_ABS) },
.absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) },
},/* A tablet like device with several gradations of pressure */
{},/* Terminating entry */
};
......
......@@ -638,16 +638,22 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
goto inval;
field = report->field[uref->field_index];
if (uref->usage_index >= field->maxusage)
goto inval;
if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
if (uref_multi->num_values >= HID_MAX_USAGES ||
uref->usage_index >= field->maxusage ||
(uref->usage_index + uref_multi->num_values) >= field->maxusage)
if (cmd == HIDIOCGCOLLECTIONINDEX) {
if (uref->usage_index >= field->maxusage)
goto inval;
} else if (uref->usage_index >= field->report_count)
goto inval;
else if ((cmd == HIDIOCGUSAGES ||
cmd == HIDIOCSUSAGES) &&
(uref->usage_index + uref_multi->num_values >=
field->report_count ||
uref->usage_index + uref_multi->num_values <
uref->usage_index))
goto inval;
}
}
switch (cmd) {
case HIDIOCGUSAGE:
......
......@@ -115,6 +115,8 @@
#include <linux/filter.h>
#include <linux/msdos_fs.h>
#include <linux/hiddev.h>
#undef INCLUDES
#endif
......
......@@ -728,3 +728,20 @@ COMPATIBLE_IOCTL(SIOCSIWRETRY)
COMPATIBLE_IOCTL(SIOCGIWRETRY)
COMPATIBLE_IOCTL(SIOCSIWPOWER)
COMPATIBLE_IOCTL(SIOCGIWPOWER)
/* hiddev */
COMPATIBLE_IOCTL(HIDIOCGVERSION)
COMPATIBLE_IOCTL(HIDIOCAPPLICATION)
COMPATIBLE_IOCTL(HIDIOCGDEVINFO)
COMPATIBLE_IOCTL(HIDIOCGSTRING)
COMPATIBLE_IOCTL(HIDIOCINITREPORT)
COMPATIBLE_IOCTL(HIDIOCGREPORT)
COMPATIBLE_IOCTL(HIDIOCSREPORT)
COMPATIBLE_IOCTL(HIDIOCGREPORTINFO)
COMPATIBLE_IOCTL(HIDIOCGFIELDINFO)
COMPATIBLE_IOCTL(HIDIOCGUSAGE)
COMPATIBLE_IOCTL(HIDIOCSUSAGE)
COMPATIBLE_IOCTL(HIDIOCGUCODE)
COMPATIBLE_IOCTL(HIDIOCGFLAG)
COMPATIBLE_IOCTL(HIDIOCSFLAG)
COMPATIBLE_IOCTL(HIDIOCGCOLLECTIONINDEX)
COMPATIBLE_IOCTL(HIDIOCGCOLLECTIONINFO)
......@@ -128,10 +128,11 @@ struct hiddev_usage_ref {
/* hiddev_usage_ref_multi is used for sending multiple bytes to a control.
* It really manifests itself as setting the value of consecutive usages */
#define HID_MAX_MULTI_USAGES 1024
struct hiddev_usage_ref_multi {
struct hiddev_usage_ref uref;
__u32 num_values;
__s32 values[HID_MAX_USAGES];
__s32 values[HID_MAX_MULTI_USAGES];
};
/* FIELD_INDEX_NONE is returned in read() data from the kernel when flags
......@@ -212,6 +213,11 @@ struct hiddev_usage_ref_multi {
* In-kernel definitions.
*/
struct hid_device;
struct hid_usage;
struct hid_field;
struct hid_report;
#ifdef CONFIG_USB_HIDDEV
int hiddev_connect(struct hid_device *);
void hiddev_disconnect(struct hid_device *);
......
......@@ -527,6 +527,8 @@ struct input_absinfo {
#define MSC_SERIAL 0x00
#define MSC_PULSELED 0x01
#define MSC_GESTURE 0x02
#define MSC_RAW 0x03
#define MSC_SCAN 0x04
#define MSC_MAX 0x07
/*
......
......@@ -17,6 +17,7 @@
#ifdef __KERNEL__
#include <linux/list.h>
#include <linux/spinlock.h>
struct serio {
void *private;
......@@ -32,11 +33,13 @@ struct serio {
unsigned long type;
unsigned long event;
spinlock_t lock;
int (*write)(struct serio *, unsigned char);
int (*open)(struct serio *);
void (*close)(struct serio *);
struct serio_dev *dev;
struct serio_dev *dev; /* Accessed from interrupt, writes must be protected by serio_lock */
struct list_head node;
};
......
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