Commit 3a53ff4d authored by Vojtech Pavlik's avatar Vojtech Pavlik

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

parents 0f19266d bcf65342
...@@ -890,8 +890,8 @@ running once the system is up. ...@@ -890,8 +890,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=
......
CHANGES CHANGES
- Created based off of scanner & INSTALL from the original touchscreen - 0.3 - Created based off of scanner & INSTALL from the original touchscreen
driver on freshmeat (http://freshmeat.net/projects/3mtouchscreendriver) driver on freshmeat (http://freshmeat.net/projects/3mtouchscreendriver)
- Amended for linux-2.4.18, then 2.4.19 - Amended for linux-2.4.18, then 2.4.19
- Complete rewrite using Linux Input in 2.6.3 - 0.5 - Complete rewrite using Linux Input in 2.6.3
Unfortunately no calibration support at this time Unfortunately no calibration support at this time
- 1.4 - Multiple changes to support the EXII 5000UC and house cleaning
Changed reset from standard USB dev reset to vendor reset
Changed data sent to host from compensated to raw coordinates
Eliminated vendor/product module params
Performed multiple successfull tests with an EXII-5010UC
DRIVER NOTES: SUPPORTED HARDWARE:
All controllers have the Vendor: 0x0596 & Product: 0x0001
Installation is simple, you only need to add Linux Input, Linux USB, and the
driver to the kernel. The driver can also be optionally built as a module.
If you have another MicroTouch device that you wish to experiment with Controller Description Part Number
or try using this driver with, but the Vendor and Product ID's are not ------------------------------------------------------
coded in, don't despair. If the driver was compiled as a module, you can
pass options to the driver. Simply try:
/sbin/modprobe mtouchusb vendor=0x#### product=0x**** USB Capacitive - Pearl Case 14-205 (Discontinued)
USB Capacitive - Black Case 14-124 (Discontinued)
USB Capacitive - No Case 14-206 (Discontinued)
If it works, send me the iVendor & iProduct (or a patch) and I will add... USB Capacitive - Pearl Case EXII-5010UC
USB Capacitive - Black Case EXII-5030UC
USB Capacitive - No Case EXII-5050UC
DRIVER NOTES:
Installation is simple, you only need to add Linux Input, Linux USB, and the
driver to the kernel. The driver can also be optionally built as a module.
This driver appears to be one of possible 2 Linux USB Input Touchscreen This driver appears to be one of possible 2 Linux USB Input Touchscreen
drivers. Although 3M produces a binary only driver available for drivers. Although 3M produces a binary only driver available for
...@@ -28,53 +40,28 @@ download, I persist in updating this driver since I would like to use the ...@@ -28,53 +40,28 @@ download, I persist in updating this driver since I would like to use the
touchscreen for embedded apps using QTEmbedded, DirectFB, etc. So I feel the touchscreen for embedded apps using QTEmbedded, DirectFB, etc. So I feel the
logical choice is to use Linux Imput. logical choice is to use Linux Imput.
A little info about the MicroTouch USB controller (14-206): Currently there is no way to calibrate the device via this driver. Even if
the device could be calibrated, the driver pulls to raw coordinate data from
Y is inverted, and the device has a total possible resolution of 0 - 65535. the controller. This means calibration must be performed within the
userspace.
Y is inverted by the driver by:
The controller screen resolution is now 0 to 16384 for both X and Y reporting
input.absmin[ABS_Y] = MTOUCHUSB_MAX_YC; the raw touch data. This is the same for the old and new capacitive USB
input.absmax[ABS_Y] = MTOUCHUSB_MIN_YC; controllers.
absmin & absmax are also used to scale the data, sine it is rather high Perhaps at some point an abstract function will be placed into evdev so
resolution. generic functions like calibrations, resets, and vendor information can be
requested from the userspace (And the drivers would handle the vendor specific
---------------touch screen area----------------- tasks).
I MicroTouch (xmax,ymax) @I
I X I ADDITIONAL INFORMATION/UPDATES/X CONFIGURATION EXAMPLE:
I ########visible monitor area############## I
I #@ (xmin,ymin) # I
I # # I
I # # I
I # # I
I # # I
I # # I
I Y # # I
I # # I
I # # I
I # # I
I # # I
I # # I
I # (xmax,ymax) @# I
I ########################################## I
I I
I@ MicroTouch (xmin,ymin) I
-------------------------------------------------
Currently there is no way to calibrate the device via this driver. Perhaps
at some point an abstract function will be placed into evdev so generic
functions like calibrations, resets, and vendor information can be requested
(And the drivers would handle the vendor specific tasks).
ADDITIONAL INFORMATION/UPDATES:
http://groomlakelabs.com/grandamp/code/microtouch/ http://groomlakelabs.com/grandamp/code/microtouch/
TODO: TODO:
Implement a control urb again to handle requests to and from the device Implement a control urb again to handle requests to and from the device
such as calibration, etc. such as calibration, etc once/if it becomes available.
DISCLAMER: DISCLAMER:
...@@ -83,3 +70,7 @@ this driver! If you want touch drivers only supported within X, please go to: ...@@ -83,3 +70,7 @@ this driver! If you want touch drivers only supported within X, please go to:
http://www.3m.com/3MTouchSystems/downloads/ http://www.3m.com/3MTouchSystems/downloads/
THANKS:
A huge thank you to 3M Touch Systems for the EXII-5010UC controllers for
testing!
...@@ -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"
......
...@@ -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");
......
...@@ -63,7 +63,6 @@ void ps2pp_process_packet(struct psmouse *psmouse) ...@@ -63,7 +63,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,17 +75,8 @@ void ps2pp_process_packet(struct psmouse *psmouse) ...@@ -76,17 +75,8 @@ 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;
for (i = 6; i >= 0; i -= 2) {
d = (command >> i) & 3;
if(psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES))
return -1; return -1;
}
if (psmouse_command(psmouse, param, PSMOUSE_CMD_POLL)) if (psmouse_command(psmouse, param, PSMOUSE_CMD_POLL))
return -1; return -1;
...@@ -113,14 +103,11 @@ static void ps2pp_set_smartscroll(struct psmouse *psmouse) ...@@ -113,14 +103,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,48 +125,47 @@ void ps2pp_set_800dpi(struct psmouse *psmouse) ...@@ -138,48 +125,47 @@ void ps2pp_set_800dpi(struct psmouse *psmouse)
psmouse_command(psmouse, &param, PSMOUSE_CMD_SETRES); psmouse_command(psmouse, &param, PSMOUSE_CMD_SETRES);
} }
static int is_model_in_list(unsigned char model, int *model_list)
{
int i;
for (i = 0; model_list[i] != -1; i++)
if (model == model_list[i])
return 1;
return 0;
}
/* /*
* Detect the exact model and features of a PS2++ or PS2T++ Logitech mouse or * Set up input device's properties based on the detected mouse model.
* touchpad.
*/ */
static int ps2pp_detect_model(struct psmouse *psmouse, unsigned char *param) static void ps2pp_set_properties(struct psmouse *psmouse, unsigned char protocol,
unsigned char model, unsigned char buttons)
{ {
int i;
static int logitech_4btn[] = { 12, 40, 41, 42, 43, 52, 73, 80, -1 }; static int logitech_4btn[] = { 12, 40, 41, 42, 43, 52, 73, 80, -1 };
static int logitech_wheel[] = { 52, 53, 75, 76, 80, 81, 83, 88, 112, -1 }; static int logitech_wheel[] = { 52, 53, 75, 76, 80, 81, 83, 88, 112, -1 };
static int logitech_ps2pp[] = { 12, 13, 40, 41, 42, 43, 50, 51, 52, 53, 73, 75,
76, 80, 81, 83, 88, 96, 97, 112, -1 };
static int logitech_mx[] = { 61, 112, -1 }; static int logitech_mx[] = { 61, 112, -1 };
psmouse->vendor = "Logitech"; psmouse->vendor = "Logitech";
psmouse->model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78); psmouse->model = model;
if (param[1] < 3) if (buttons < 3)
clear_bit(BTN_MIDDLE, psmouse->dev.keybit); clear_bit(BTN_MIDDLE, psmouse->dev.keybit);
if (param[1] < 2) if (buttons < 2)
clear_bit(BTN_RIGHT, psmouse->dev.keybit); clear_bit(BTN_RIGHT, psmouse->dev.keybit);
psmouse->type = PSMOUSE_PS2; if (protocol == PSMOUSE_PS2PP) {
for (i = 0; logitech_ps2pp[i] != -1; i++)
if (logitech_ps2pp[i] == psmouse->model)
psmouse->type = PSMOUSE_PS2PP;
if (psmouse->type == PSMOUSE_PS2PP) {
for (i = 0; logitech_4btn[i] != -1; i++) if (is_model_in_list(model, logitech_4btn))
if (logitech_4btn[i] == psmouse->model)
set_bit(BTN_SIDE, psmouse->dev.keybit); set_bit(BTN_SIDE, psmouse->dev.keybit);
for (i = 0; logitech_wheel[i] != -1; i++) if (is_model_in_list(model, logitech_wheel)) {
if (logitech_wheel[i] == psmouse->model) {
set_bit(REL_WHEEL, psmouse->dev.relbit); set_bit(REL_WHEEL, psmouse->dev.relbit);
psmouse->name = "Wheel Mouse"; psmouse->name = "Wheel Mouse";
} }
for (i = 0; logitech_mx[i] != -1; i++) if (is_model_in_list(model, logitech_mx)) {
if (logitech_mx[i] == psmouse->model) {
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);
set_bit(BTN_BACK, psmouse->dev.keybit); set_bit(BTN_BACK, psmouse->dev.keybit);
...@@ -187,62 +173,80 @@ static int ps2pp_detect_model(struct psmouse *psmouse, unsigned char *param) ...@@ -187,62 +173,80 @@ static int ps2pp_detect_model(struct psmouse *psmouse, unsigned char *param)
set_bit(BTN_TASK, psmouse->dev.keybit); set_bit(BTN_TASK, psmouse->dev.keybit);
psmouse->name = "MX Mouse"; psmouse->name = "MX Mouse";
} }
}
if (protocol == PSMOUSE_PS2TPP) {
set_bit(REL_WHEEL, psmouse->dev.relbit);
set_bit(REL_HWHEEL, psmouse->dev.relbit);
psmouse->name = "TouchPad 3";
}
}
/* /*
* 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->model == 97) { /* TouchPad 3 */ int ps2pp_init(struct psmouse *psmouse, int set_properties)
{
static int logitech_ps2pp[] = { 12, 13, 40, 41, 42, 43, 50, 51, 52, 53, 73, 75,
76, 80, 81, 83, 88, 96, 97, 112, -1 };
unsigned char param[4];
unsigned char protocol = PSMOUSE_PS2;
unsigned char model, buttons;
param[0] = 0;
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);
set_bit(REL_WHEEL, psmouse->dev.relbit); if (param[1] != 0) {
set_bit(REL_HWHEEL, psmouse->dev.relbit); model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78);
buttons = param[1];
/*
* Do Logitech PS2++ / PS2T++ magic init.
*/
if (model == 97) { /* Touch Pad 3 */
param[0] = 0x11; param[1] = 0x04; param[2] = 0x68; /* Unprotect RAM */ /* 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 (is_model_in_list(model, logitech_ps2pp)) {
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)
} ps2pp_set_properties(psmouse, protocol, model, buttons);
}
/*
* Logitech magic init.
*/
int ps2pp_detect(struct psmouse *psmouse)
{
unsigned char param[4];
param[0] = 0;
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);
return param[1] != 0 ? ps2pp_detect_model(psmouse, param) : 0; return protocol;
} }
...@@ -10,8 +10,9 @@ ...@@ -10,8 +10,9 @@
#ifndef _LOGIPS2PP_H #ifndef _LOGIPS2PP_H
#define _LOGIPS2PP_H #define _LOGIPS2PP_H
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,23 +410,23 @@ static int im_explorer_detect(struct psmouse *psmouse) ...@@ -363,23 +410,23 @@ 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 (synaptics_init(psmouse) == 0)
return PSMOUSE_SYNAPTICS; return PSMOUSE_SYNAPTICS;
/* /*
...@@ -387,7 +434,7 @@ static int psmouse_extensions(struct psmouse *psmouse) ...@@ -387,7 +434,7 @@ static int psmouse_extensions(struct psmouse *psmouse)
* 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,45 @@ static int psmouse_extensions(struct psmouse *psmouse) ...@@ -395,35 +442,45 @@ 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_IMPS && intellimouse_detect(psmouse)) {
if (set_properties) {
set_bit(REL_WHEEL, psmouse->dev.relbit); set_bit(REL_WHEEL, psmouse->dev.relbit);
if (!psmouse->name)
psmouse->name = "Wheel Mouse";
}
if (max_proto >= PSMOUSE_IMEX && im_explorer_detect(psmouse)) {
if (psmouse_max_proto >= PSMOUSE_IMEX && if (!set_properties) {
im_explorer_detect(psmouse)) {
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;
} }
psmouse->name = "Wheel Mouse";
return PSMOUSE_IMPS; return PSMOUSE_IMPS;
} }
...@@ -473,12 +530,7 @@ static int psmouse_probe(struct psmouse *psmouse) ...@@ -473,12 +530,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 +668,6 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev) ...@@ -616,7 +668,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 +679,21 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev) ...@@ -628,13 +679,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 +727,24 @@ static int psmouse_reconnect(struct serio *serio) ...@@ -668,27 +727,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 */
...@@ -43,34 +43,12 @@ ...@@ -43,34 +43,12 @@
* Synaptics communications functions * Synaptics communications functions
****************************************************************************/ ****************************************************************************/
/*
* Use the Synaptics extended ps/2 syntax to write a special command byte.
* special command: 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu
* is the command. A 0xF3 or 0xE9 must follow (see synaptics_send_cmd
* and synaptics_mode_cmd)
*/
static int synaptics_special_cmd(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;
}
/* /*
* Send a command to the synpatics touchpad by special commands * Send a command to the synpatics touchpad by special commands
*/ */
static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param) static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param)
{ {
if (synaptics_special_cmd(psmouse, c)) if (psmouse_sliced_command(psmouse, c))
return -1; return -1;
if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO)) if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO))
return -1; return -1;
...@@ -84,7 +62,7 @@ static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode) ...@@ -84,7 +62,7 @@ static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode)
{ {
unsigned char param[1]; unsigned char param[1];
if (synaptics_special_cmd(psmouse, mode)) if (psmouse_sliced_command(psmouse, mode))
return -1; return -1;
param[0] = SYN_PS_SET_MODE2; param[0] = SYN_PS_SET_MODE2;
if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE)) if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE))
...@@ -118,17 +96,31 @@ static int synaptics_capability(struct psmouse *psmouse) ...@@ -118,17 +96,31 @@ static int synaptics_capability(struct psmouse *psmouse)
if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap)) if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap))
return -1; return -1;
priv->capabilities = (cap[0]<<16) | (cap[1]<<8) | cap[2]; priv->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2];
priv->ext_cap = 0; priv->ext_cap = 0;
if (!SYN_CAP_VALID(priv->capabilities)) if (!SYN_CAP_VALID(priv->capabilities))
return -1; return -1;
if (SYN_EXT_CAP_REQUESTS(priv->capabilities)) { /*
* Unless capExtended is set the rest of the flags should be ignored
*/
if (!SYN_CAP_EXTENDED(priv->capabilities))
priv->capabilities = 0;
if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 1) {
if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) { if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) {
printk(KERN_ERR "Synaptics claims to have extended capabilities," printk(KERN_ERR "Synaptics claims to have extended capabilities,"
" but I'm not able to read them."); " but I'm not able to read them.");
} else } else {
priv->ext_cap = (cap[0]<<16) | (cap[1]<<8) | cap[2]; priv->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2];
/*
* if nExtBtn is greater than 8 it should be considered
* invalid and treated as 0
*/
if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) > 8)
priv->ext_cap &= 0xff0fff;
}
} }
return 0; return 0;
} }
...@@ -167,11 +159,12 @@ static void print_ident(struct synaptics_data *priv) ...@@ -167,11 +159,12 @@ static void print_ident(struct synaptics_data *priv)
if (SYN_CAP_EXTENDED(priv->capabilities)) { if (SYN_CAP_EXTENDED(priv->capabilities)) {
printk(KERN_INFO " Touchpad has extended capability bits\n"); printk(KERN_INFO " Touchpad has extended capability bits\n");
if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) && if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) <= 8)
printk(KERN_INFO " -> %d multi-buttons, i.e. besides standard buttons\n", printk(KERN_INFO " -> %d multi-buttons, i.e. besides standard buttons\n",
(int)(SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))); (int)(SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap)));
else if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
printk(KERN_INFO " -> middle button\n");
if (SYN_CAP_FOUR_BUTTON(priv->capabilities))
printk(KERN_INFO " -> four buttons\n"); printk(KERN_INFO " -> four buttons\n");
if (SYN_CAP_MULTIFINGER(priv->capabilities)) if (SYN_CAP_MULTIFINGER(priv->capabilities))
printk(KERN_INFO " -> multifinger detection\n"); printk(KERN_INFO " -> multifinger detection\n");
...@@ -219,21 +212,12 @@ static int synaptics_set_mode(struct psmouse *psmouse, int mode) ...@@ -219,21 +212,12 @@ static int synaptics_set_mode(struct psmouse *psmouse, int mode)
/***************************************************************************** /*****************************************************************************
* Synaptics pass-through PS/2 port support * Synaptics pass-through PS/2 port support
****************************************************************************/ ****************************************************************************/
static int synaptics_pt_open(struct serio *port)
{
return 0;
}
static void synaptics_pt_close(struct serio *port)
{
}
static int synaptics_pt_write(struct serio *port, unsigned char c) static int synaptics_pt_write(struct serio *port, unsigned char c)
{ {
struct psmouse *parent = port->driver; struct psmouse *parent = port->driver;
char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */ char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */
if (synaptics_special_cmd(parent, c)) if (psmouse_sliced_command(parent, c))
return -1; return -1;
if (psmouse_command(parent, &rate_param, PSMOUSE_CMD_SETRATE)) if (psmouse_command(parent, &rate_param, PSMOUSE_CMD_SETRATE))
return -1; return -1;
...@@ -289,165 +273,11 @@ static void synaptics_pt_create(struct psmouse *psmouse) ...@@ -289,165 +273,11 @@ static void synaptics_pt_create(struct psmouse *psmouse)
port->serio.name = "Synaptics pass-through"; port->serio.name = "Synaptics pass-through";
port->serio.phys = "synaptics-pt/serio0"; port->serio.phys = "synaptics-pt/serio0";
port->serio.write = synaptics_pt_write; port->serio.write = synaptics_pt_write;
port->serio.open = synaptics_pt_open;
port->serio.close = synaptics_pt_close;
port->serio.driver = psmouse; port->serio.driver = psmouse;
port->activate = synaptics_pt_activate; port->activate = synaptics_pt_activate;
} }
/*****************************************************************************
* Driver initialization/cleanup functions
****************************************************************************/
static inline void 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;
set_bit(axis, dev->absbit);
}
static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
{
set_bit(EV_ABS, dev->evbit);
set_abs_params(dev, ABS_X, XMIN_NOMINAL, XMAX_NOMINAL, 0, 0);
set_abs_params(dev, ABS_Y, YMIN_NOMINAL, YMAX_NOMINAL, 0, 0);
set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
set_bit(ABS_TOOL_WIDTH, dev->absbit);
set_bit(EV_KEY, dev->evbit);
set_bit(BTN_TOUCH, dev->keybit);
set_bit(BTN_TOOL_FINGER, dev->keybit);
set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
set_bit(BTN_LEFT, dev->keybit);
set_bit(BTN_RIGHT, dev->keybit);
set_bit(BTN_FORWARD, dev->keybit);
set_bit(BTN_BACK, dev->keybit);
if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap)) {
switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
default:
/*
* if nExtBtn is greater than 8 it should be considered
* invalid and treated as 0
*/
break;
case 8:
set_bit(BTN_7, dev->keybit);
set_bit(BTN_6, dev->keybit);
case 6:
set_bit(BTN_5, dev->keybit);
set_bit(BTN_4, dev->keybit);
case 4:
set_bit(BTN_3, dev->keybit);
set_bit(BTN_2, dev->keybit);
case 2:
set_bit(BTN_1, dev->keybit);
set_bit(BTN_0, dev->keybit);
break;
}
}
clear_bit(EV_REL, dev->evbit);
clear_bit(REL_X, dev->relbit);
clear_bit(REL_Y, dev->relbit);
}
void synaptics_reset(struct psmouse *psmouse)
{
/* reset touchpad back to relative mode, gestures enabled */
synaptics_mode_cmd(psmouse, 0);
}
static void synaptics_disconnect(struct psmouse *psmouse)
{
synaptics_reset(psmouse);
kfree(psmouse->private);
}
static int synaptics_reconnect(struct psmouse *psmouse)
{
struct synaptics_data *priv = psmouse->private;
struct synaptics_data old_priv = *priv;
if (!synaptics_detect(psmouse))
return -1;
if (synaptics_query_hardware(psmouse)) {
printk(KERN_ERR "Unable to query Synaptics hardware.\n");
return -1;
}
if (old_priv.identity != priv->identity ||
old_priv.model_id != priv->model_id ||
old_priv.capabilities != priv->capabilities ||
old_priv.ext_cap != priv->ext_cap)
return -1;
if (synaptics_set_mode(psmouse, 0)) {
printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
return -1;
}
return 0;
}
int synaptics_detect(struct psmouse *psmouse)
{
unsigned char param[4];
param[0] = 0;
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);
psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
return param[1] == 0x47;
}
int synaptics_init(struct psmouse *psmouse)
{
struct synaptics_data *priv;
psmouse->private = priv = kmalloc(sizeof(struct synaptics_data), GFP_KERNEL);
if (!priv)
return -1;
memset(priv, 0, sizeof(struct synaptics_data));
if (synaptics_query_hardware(psmouse)) {
printk(KERN_ERR "Unable to query Synaptics hardware.\n");
goto init_fail;
}
if (synaptics_set_mode(psmouse, 0)) {
printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
goto init_fail;
}
priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
if (SYN_CAP_EXTENDED(priv->capabilities) && SYN_CAP_PASS_THROUGH(priv->capabilities))
synaptics_pt_create(psmouse);
print_ident(priv);
set_input_params(&psmouse->dev, priv);
psmouse->disconnect = synaptics_disconnect;
psmouse->reconnect = synaptics_reconnect;
return 0;
init_fail:
kfree(priv);
return -1;
}
/***************************************************************************** /*****************************************************************************
* Functions to interpret the absolute mode packets * Functions to interpret the absolute mode packets
****************************************************************************/ ****************************************************************************/
...@@ -471,17 +301,17 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data ...@@ -471,17 +301,17 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data
hw->left = (buf[0] & 0x01) ? 1 : 0; hw->left = (buf[0] & 0x01) ? 1 : 0;
hw->right = (buf[0] & 0x02) ? 1 : 0; hw->right = (buf[0] & 0x02) ? 1 : 0;
if (SYN_CAP_EXTENDED(priv->capabilities) &&
(SYN_CAP_FOUR_BUTTON(priv->capabilities))) { if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
hw->up = ((buf[3] & 0x01)) ? 1 : 0; hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
if (hw->left)
hw->up = !hw->up; if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
hw->down = ((buf[3] & 0x02)) ? 1 : 0; hw->up = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
if (hw->right) hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0;
hw->down = !hw->down;
} }
if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) && if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) &&
((buf[3] & 2) ? !hw->right : hw->right)) { ((buf[0] ^ buf[3]) & 0x02)) {
switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) { switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
default: default:
/* /*
...@@ -490,17 +320,17 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data ...@@ -490,17 +320,17 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data
*/ */
break; break;
case 8: case 8:
hw->b7 = ((buf[5] & 0x08)) ? 1 : 0; hw->ext_buttons |= ((buf[5] & 0x08)) ? 0x80 : 0;
hw->b6 = ((buf[4] & 0x08)) ? 1 : 0; hw->ext_buttons |= ((buf[4] & 0x08)) ? 0x40 : 0;
case 6: case 6:
hw->b5 = ((buf[5] & 0x04)) ? 1 : 0; hw->ext_buttons |= ((buf[5] & 0x04)) ? 0x20 : 0;
hw->b4 = ((buf[4] & 0x04)) ? 1 : 0; hw->ext_buttons |= ((buf[4] & 0x04)) ? 0x10 : 0;
case 4: case 4:
hw->b3 = ((buf[5] & 0x02)) ? 1 : 0; hw->ext_buttons |= ((buf[5] & 0x02)) ? 0x08 : 0;
hw->b2 = ((buf[4] & 0x02)) ? 1 : 0; hw->ext_buttons |= ((buf[4] & 0x02)) ? 0x04 : 0;
case 2: case 2:
hw->b1 = ((buf[5] & 0x01)) ? 1 : 0; hw->ext_buttons |= ((buf[5] & 0x01)) ? 0x02 : 0;
hw->b0 = ((buf[4] & 0x01)) ? 1 : 0; hw->ext_buttons |= ((buf[4] & 0x01)) ? 0x01 : 0;
} }
} }
} else { } else {
...@@ -525,6 +355,7 @@ static void synaptics_process_packet(struct psmouse *psmouse) ...@@ -525,6 +355,7 @@ static void synaptics_process_packet(struct psmouse *psmouse)
struct synaptics_hw_state hw; struct synaptics_hw_state hw;
int num_fingers; int num_fingers;
int finger_width; int finger_width;
int i;
synaptics_parse_hw_state(psmouse->packet, priv, &hw); synaptics_parse_hw_state(psmouse->packet, priv, &hw);
...@@ -572,30 +403,18 @@ static void synaptics_process_packet(struct psmouse *psmouse) ...@@ -572,30 +403,18 @@ static void synaptics_process_packet(struct psmouse *psmouse)
input_report_key(dev, BTN_LEFT, hw.left); input_report_key(dev, BTN_LEFT, hw.left);
input_report_key(dev, BTN_RIGHT, hw.right); input_report_key(dev, BTN_RIGHT, hw.right);
if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
input_report_key(dev, BTN_MIDDLE, hw.middle);
if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
input_report_key(dev, BTN_FORWARD, hw.up); input_report_key(dev, BTN_FORWARD, hw.up);
input_report_key(dev, BTN_BACK, hw.down); input_report_key(dev, BTN_BACK, hw.down);
if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
switch(SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
default:
/*
* if nExtBtn is greater than 8 it should be considered
* invalid and treated as 0
*/
break;
case 8:
input_report_key(dev, BTN_7, hw.b7);
input_report_key(dev, BTN_6, hw.b6);
case 6:
input_report_key(dev, BTN_5, hw.b5);
input_report_key(dev, BTN_4, hw.b4);
case 4:
input_report_key(dev, BTN_3, hw.b3);
input_report_key(dev, BTN_2, hw.b2);
case 2:
input_report_key(dev, BTN_1, hw.b1);
input_report_key(dev, BTN_0, hw.b0);
break;
} }
for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
input_report_key(dev, BTN_0 + i, hw.ext_buttons & (1 << i));
input_sync(dev); input_sync(dev);
} }
...@@ -607,6 +426,9 @@ static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned cha ...@@ -607,6 +426,9 @@ static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned cha
static unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 }; static unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 };
static unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 }; static unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 };
if (idx < 0 || idx > 4)
return 0;
switch (pkt_type) { switch (pkt_type) {
case SYN_NEWABS: case SYN_NEWABS:
case SYN_NEWABS_RELAXED: case SYN_NEWABS_RELAXED:
...@@ -637,7 +459,7 @@ static unsigned char synaptics_detect_pkt_type(struct psmouse *psmouse) ...@@ -637,7 +459,7 @@ static unsigned char synaptics_detect_pkt_type(struct psmouse *psmouse)
return SYN_NEWABS_STRICT; return SYN_NEWABS_STRICT;
} }
void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs) static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
{ {
struct input_dev *dev = &psmouse->dev; struct input_dev *dev = &psmouse->dev;
struct synaptics_data *priv = psmouse->private; struct synaptics_data *priv = psmouse->private;
...@@ -645,11 +467,6 @@ void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs) ...@@ -645,11 +467,6 @@ void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
input_regs(dev, regs); input_regs(dev, regs);
if (psmouse->pktcnt >= 6) { /* Full packet received */ if (psmouse->pktcnt >= 6) { /* Full packet received */
if (priv->out_of_sync) {
priv->out_of_sync = 0;
printk(KERN_NOTICE "Synaptics driver resynced.\n");
}
if (unlikely(priv->pkt_type == SYN_NEWABS)) if (unlikely(priv->pkt_type == SYN_NEWABS))
priv->pkt_type = synaptics_detect_pkt_type(psmouse); priv->pkt_type = synaptics_detect_pkt_type(psmouse);
...@@ -657,16 +474,142 @@ void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs) ...@@ -657,16 +474,142 @@ void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
synaptics_pass_pt_packet(&psmouse->ptport->serio, psmouse->packet); synaptics_pass_pt_packet(&psmouse->ptport->serio, psmouse->packet);
else else
synaptics_process_packet(psmouse); synaptics_process_packet(psmouse);
psmouse->pktcnt = 0;
return PSMOUSE_FULL_PACKET;
} else if (psmouse->pktcnt && }
!synaptics_validate_byte(psmouse->packet, psmouse->pktcnt - 1, priv->pkt_type)) {
printk(KERN_WARNING "Synaptics driver lost sync at byte %d\n", psmouse->pktcnt); return synaptics_validate_byte(psmouse->packet, psmouse->pktcnt - 1, priv->pkt_type) ?
psmouse->pktcnt = 0; PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
if (++priv->out_of_sync == psmouse_resetafter) { }
psmouse->state = PSMOUSE_IGNORE;
printk(KERN_NOTICE "synaptics: issuing reconnect request\n"); /*****************************************************************************
serio_reconnect(psmouse->serio); * Driver initialization/cleanup functions
****************************************************************************/
static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
{
int i;
set_bit(EV_ABS, dev->evbit);
input_set_abs_params(dev, ABS_X, XMIN_NOMINAL, XMAX_NOMINAL, 0, 0);
input_set_abs_params(dev, ABS_Y, YMIN_NOMINAL, YMAX_NOMINAL, 0, 0);
input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
set_bit(ABS_TOOL_WIDTH, dev->absbit);
set_bit(EV_KEY, dev->evbit);
set_bit(BTN_TOUCH, dev->keybit);
set_bit(BTN_TOOL_FINGER, dev->keybit);
set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
set_bit(BTN_LEFT, dev->keybit);
set_bit(BTN_RIGHT, dev->keybit);
if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
set_bit(BTN_MIDDLE, dev->keybit);
if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
set_bit(BTN_FORWARD, dev->keybit);
set_bit(BTN_BACK, dev->keybit);
}
for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
set_bit(BTN_0 + i, dev->keybit);
clear_bit(EV_REL, dev->evbit);
clear_bit(REL_X, dev->relbit);
clear_bit(REL_Y, dev->relbit);
}
void synaptics_reset(struct psmouse *psmouse)
{
/* reset touchpad back to relative mode, gestures enabled */
synaptics_mode_cmd(psmouse, 0);
}
static void synaptics_disconnect(struct psmouse *psmouse)
{
synaptics_reset(psmouse);
kfree(psmouse->private);
}
static int synaptics_reconnect(struct psmouse *psmouse)
{
struct synaptics_data *priv = psmouse->private;
struct synaptics_data old_priv = *priv;
if (!synaptics_detect(psmouse))
return -1;
if (synaptics_query_hardware(psmouse)) {
printk(KERN_ERR "Unable to query Synaptics hardware.\n");
return -1;
}
if (old_priv.identity != priv->identity ||
old_priv.model_id != priv->model_id ||
old_priv.capabilities != priv->capabilities ||
old_priv.ext_cap != priv->ext_cap)
return -1;
if (synaptics_set_mode(psmouse, 0)) {
printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
return -1;
}
return 0;
}
int synaptics_detect(struct psmouse *psmouse)
{
unsigned char param[4];
param[0] = 0;
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);
psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
return param[1] == 0x47;
}
int synaptics_init(struct psmouse *psmouse)
{
struct synaptics_data *priv;
psmouse->private = priv = kmalloc(sizeof(struct synaptics_data), GFP_KERNEL);
if (!priv)
return -1;
memset(priv, 0, sizeof(struct synaptics_data));
if (synaptics_query_hardware(psmouse)) {
printk(KERN_ERR "Unable to query Synaptics hardware.\n");
goto init_fail;
} }
if (synaptics_set_mode(psmouse, 0)) {
printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
goto init_fail;
} }
priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
if (SYN_CAP_PASS_THROUGH(priv->capabilities))
synaptics_pt_create(psmouse);
print_ident(priv);
set_input_params(&psmouse->dev, priv);
psmouse->protocol_handler = synaptics_process_byte;
psmouse->disconnect = synaptics_disconnect;
psmouse->reconnect = synaptics_reconnect;
return 0;
init_fail:
kfree(priv);
return -1;
} }
...@@ -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 */
}; };
......
...@@ -391,9 +391,9 @@ static ssize_t mousedev_write(struct file * file, const char * buffer, size_t co ...@@ -391,9 +391,9 @@ static ssize_t mousedev_write(struct file * file, const char * buffer, size_t co
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;
} }
......
...@@ -474,8 +474,17 @@ static int i8042_enable_mux_mode(struct i8042_values *values, unsigned char *mux ...@@ -474,8 +474,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 +541,8 @@ static int __init i8042_check_mux(struct i8042_values *values) ...@@ -532,8 +541,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",
......
...@@ -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;
......
...@@ -397,17 +397,12 @@ static void h3600ts_connect(struct serio *serio, struct serio_dev *dev) ...@@ -397,17 +397,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 +417,9 @@ static void h3600ts_connect(struct serio *serio, struct serio_dev *dev) ...@@ -422,6 +417,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;
......
...@@ -28,6 +28,12 @@ ...@@ -28,6 +28,12 @@
* Complete rewrite using Linux Input in 2.6.3 * Complete rewrite using Linux Input in 2.6.3
* Unfortunately no calibration support at this time * Unfortunately no calibration support at this time
* *
* 1.4 04/25/2004 (TEJ) tejohnson@yahoo.com
* Changed reset from standard USB dev reset to vendor reset
* Changed data sent to host from compensated to raw coordinates
* Eliminated vendor/product module params
* Performed multiple successfull tests with an EXII-5010UC
*
*****************************************************************************/ *****************************************************************************/
#include <linux/config.h> #include <linux/config.h>
...@@ -45,25 +51,28 @@ ...@@ -45,25 +51,28 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/usb.h> #include <linux/usb.h>
#define MTOUCHUSB_MIN_XC 0xc8 #define MTOUCHUSB_MIN_XC 0x0
#define MTOUCHUSB_MAX_XC 0xff78 #define MTOUCHUSB_MAX_XC 0x4000
#define MTOUCHUSB_XC_FUZZ 0x0 #define MTOUCHUSB_XC_FUZZ 0x0
#define MTOUCHUSB_XC_FLAT 0x0 #define MTOUCHUSB_XC_FLAT 0x0
#define MTOUCHUSB_MIN_YC 0x0 #define MTOUCHUSB_MIN_YC 0x0
#define MTOUCHUSB_MAX_YC 0xff78 #define MTOUCHUSB_MAX_YC 0x4000
#define MTOUCHUSB_YC_FUZZ 0x0 #define MTOUCHUSB_YC_FUZZ 0x0
#define MTOUCHUSB_YC_FLAT 0x0 #define MTOUCHUSB_YC_FLAT 0x0
#define MTOUCHUSB_ASYC_REPORT 1
#define MTOUCHUSB_REPORT_SIZE_DATA 11 #define MTOUCHUSB_ASYNC_REPORT 1
#define MTOUCHUSB_RESET 7
#define MTOUCHUSB_REPORT_DATA_SIZE 11
#define MTOUCHUSB_REQ_CTRLLR_ID 10 #define MTOUCHUSB_REQ_CTRLLR_ID 10
#define MTOUCHUSB_GET_XC(data) (data[4]<<8 | data[3]) #define MTOUCHUSB_GET_XC(data) (data[8]<<8 | data[7])
#define MTOUCHUSB_GET_YC(data) (data[6]<<8 | data[5]) #define MTOUCHUSB_GET_YC(data) (data[10]<<8 | data[9])
#define MTOUCHUSB_GET_TOUCHED(data) ((data[2] & 0x40) ? 1:0) #define MTOUCHUSB_GET_TOUCHED(data) ((data[2] & 0x40) ? 1:0)
#define DRIVER_VERSION "v0.1" #define DRIVER_VERSION "v1.4"
#define DRIVER_AUTHOR "Todd E. Johnson, tejohnson@yahoo.com" #define DRIVER_AUTHOR "Todd E. Johnson, tejohnson@yahoo.com"
#define DRIVER_DESC "Microtouch USB HID Touchscreen Driver" #define DRIVER_DESC "3M USB Touchscreen Driver"
#define DRIVER_LICENSE "GPL"
struct mtouch_usb { struct mtouch_usb {
unsigned char *data; unsigned char *data;
...@@ -76,11 +85,9 @@ struct mtouch_usb { ...@@ -76,11 +85,9 @@ struct mtouch_usb {
char phys[64]; char phys[64];
}; };
static __s32 vendor=-1, product=-1;
static struct usb_device_id mtouchusb_devices [] = { static struct usb_device_id mtouchusb_devices [] = {
{ USB_DEVICE(0x0596, 0x0001) }, /* 3M (Formerly MicroTouch) 14-206 */ { USB_DEVICE(0x0596, 0x0001) },
{ } /* Terminating entry */ { }
}; };
static void mtouchusb_irq(struct urb *urb, struct pt_regs *regs) static void mtouchusb_irq(struct urb *urb, struct pt_regs *regs)
...@@ -153,7 +160,7 @@ static int mtouchusb_alloc_buffers(struct usb_device *udev, struct mtouch_usb *m ...@@ -153,7 +160,7 @@ static int mtouchusb_alloc_buffers(struct usb_device *udev, struct mtouch_usb *m
{ {
dbg("%s - called", __FUNCTION__); dbg("%s - called", __FUNCTION__);
mtouch->data = usb_buffer_alloc(udev, MTOUCHUSB_REPORT_SIZE_DATA, mtouch->data = usb_buffer_alloc(udev, MTOUCHUSB_REPORT_DATA_SIZE,
SLAB_ATOMIC, &mtouch->data_dma); SLAB_ATOMIC, &mtouch->data_dma);
if (!mtouch->data) if (!mtouch->data)
...@@ -167,7 +174,7 @@ static void mtouchusb_free_buffers(struct usb_device *udev, struct mtouch_usb *m ...@@ -167,7 +174,7 @@ static void mtouchusb_free_buffers(struct usb_device *udev, struct mtouch_usb *m
dbg("%s - called", __FUNCTION__); dbg("%s - called", __FUNCTION__);
if (mtouch->data) if (mtouch->data)
usb_buffer_free(udev, MTOUCHUSB_REPORT_SIZE_DATA, usb_buffer_free(udev, MTOUCHUSB_REPORT_DATA_SIZE,
mtouch->data, mtouch->data_dma); mtouch->data, mtouch->data_dma);
} }
...@@ -180,41 +187,8 @@ static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_i ...@@ -180,41 +187,8 @@ static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_i
char path[64]; char path[64];
char *buf; char *buf;
int nRet; int nRet;
int ix;
char valid_device = 0;
dbg("%s - called", __FUNCTION__); dbg("%s - called", __FUNCTION__);
if (vendor != -1 && product != -1) {
info("%s - User specified USB Touch -- Vend:Prod - %x:%x",
__FUNCTION__, vendor, product);
}
for (ix = 0; ix < sizeof (mtouchusb_devices) /
sizeof (struct usb_device_id); ix++) {
if ((udev->descriptor.idVendor ==
mtouchusb_devices [ix].idVendor) &&
(udev->descriptor.idProduct ==
mtouchusb_devices [ix].idProduct)) {
valid_device = 1;
break;
}
}
if (udev->descriptor.idVendor == vendor &&
udev->descriptor.idProduct == product) { /* User specified */
valid_device = 1;
}
if (!valid_device) {
err("%s - No valid device!", __FUNCTION__);
return -EIO;
}
if (udev->descriptor.bNumConfigurations != 1) {
err("%s - Only one device configuration is supported.",
__FUNCTION__);
return -EIO;
}
dbg("%s - setting interface", __FUNCTION__); dbg("%s - setting interface", __FUNCTION__);
interface = intf->cur_altsetting; interface = intf->cur_altsetting;
...@@ -222,11 +196,6 @@ static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_i ...@@ -222,11 +196,6 @@ static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_i
dbg("%s - setting endpoint", __FUNCTION__); dbg("%s - setting endpoint", __FUNCTION__);
endpoint = &interface->endpoint[0].desc; endpoint = &interface->endpoint[0].desc;
if (interface->desc.bNumEndpoints != 1) {
err("%s - Only one endpoint is supported.", __FUNCTION__);
return -EIO;
}
if (!(mtouch = kmalloc (sizeof (struct mtouch_usb), GFP_KERNEL))) { if (!(mtouch = kmalloc (sizeof (struct mtouch_usb), GFP_KERNEL))) {
err("%s - Out of memory.", __FUNCTION__); err("%s - Out of memory.", __FUNCTION__);
return -ENOMEM; return -ENOMEM;
...@@ -266,8 +235,8 @@ static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_i ...@@ -266,8 +235,8 @@ static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_i
mtouch->input.absmax[ABS_X] = MTOUCHUSB_MAX_XC; mtouch->input.absmax[ABS_X] = MTOUCHUSB_MAX_XC;
mtouch->input.absfuzz[ABS_X] = MTOUCHUSB_XC_FUZZ; mtouch->input.absfuzz[ABS_X] = MTOUCHUSB_XC_FUZZ;
mtouch->input.absflat[ABS_X] = MTOUCHUSB_XC_FLAT; mtouch->input.absflat[ABS_X] = MTOUCHUSB_XC_FLAT;
mtouch->input.absmin[ABS_Y] = MTOUCHUSB_MAX_YC; mtouch->input.absmin[ABS_Y] = MTOUCHUSB_MIN_YC;
mtouch->input.absmax[ABS_Y] = MTOUCHUSB_MIN_YC; mtouch->input.absmax[ABS_Y] = MTOUCHUSB_MAX_YC;
mtouch->input.absfuzz[ABS_Y] = MTOUCHUSB_YC_FUZZ; mtouch->input.absfuzz[ABS_Y] = MTOUCHUSB_YC_FUZZ;
mtouch->input.absflat[ABS_Y] = MTOUCHUSB_YC_FLAT; mtouch->input.absflat[ABS_Y] = MTOUCHUSB_YC_FLAT;
...@@ -290,15 +259,15 @@ static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_i ...@@ -290,15 +259,15 @@ static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_i
kfree(buf); kfree(buf);
nRet = usb_control_msg(mtouch->udev, nRet = usb_control_msg(mtouch->udev,
usb_rcvctrlpipe(udev, 0x80), usb_rcvctrlpipe(udev, 0),
USB_REQ_GET_CONFIGURATION, MTOUCHUSB_RESET,
USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1,
0, 0,
0x81,
NULL, NULL,
0, 0,
HZ * USB_CTRL_SET_TIMEOUT); HZ * USB_CTRL_SET_TIMEOUT);
dbg("%s - usb_control_msg - USB_REQ_GET_CONFIGURATION - bytes|err: %d", dbg("%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d",
__FUNCTION__, nRet); __FUNCTION__, nRet);
dbg("%s - usb_alloc_urb: mtouch->irq", __FUNCTION__); dbg("%s - usb_alloc_urb: mtouch->irq", __FUNCTION__);
...@@ -315,7 +284,7 @@ static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_i ...@@ -315,7 +284,7 @@ static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_i
mtouch->udev, mtouch->udev,
usb_rcvintpipe(mtouch->udev, 0x81), usb_rcvintpipe(mtouch->udev, 0x81),
mtouch->data, mtouch->data,
MTOUCHUSB_REPORT_SIZE_DATA, MTOUCHUSB_REPORT_DATA_SIZE,
mtouchusb_irq, mtouchusb_irq,
mtouch, mtouch,
endpoint->bInterval); endpoint->bInterval);
...@@ -324,15 +293,15 @@ static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_i ...@@ -324,15 +293,15 @@ static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_i
input_register_device(&mtouch->input); input_register_device(&mtouch->input);
nRet = usb_control_msg(mtouch->udev, nRet = usb_control_msg(mtouch->udev,
usb_rcvctrlpipe(udev, 0x80), usb_rcvctrlpipe(udev, 0),
MTOUCHUSB_ASYC_REPORT, MTOUCHUSB_ASYNC_REPORT,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
MTOUCHUSB_ASYC_REPORT, 1,
MTOUCHUSB_ASYC_REPORT, 1,
NULL, NULL,
0, 0,
HZ * USB_CTRL_SET_TIMEOUT); HZ * USB_CTRL_SET_TIMEOUT);
dbg("%s - usb_control_msg - MTOUCHUSB_ASYC_REPORT - bytes|err: %d", dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d",
__FUNCTION__, nRet); __FUNCTION__, nRet);
printk(KERN_INFO "input: %s on %s\n", mtouch->name, path); printk(KERN_INFO "input: %s on %s\n", mtouch->name, path);
...@@ -383,9 +352,3 @@ module_exit(mtouchusb_cleanup); ...@@ -383,9 +352,3 @@ module_exit(mtouchusb_cleanup);
MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_AUTHOR( DRIVER_AUTHOR );
MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_DESCRIPTION( DRIVER_DESC );
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_PARM(vendor, "i");
MODULE_PARM_DESC(vendor, "User specified USB idVendor");
MODULE_PARM(product, "i");
MODULE_PARM_DESC(product, "User specified USB idProduct");
...@@ -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