Commit 7e1bfc50 authored by Dmitry Torokhov's avatar Dmitry Torokhov

Merge with Linus' tree

parents 3d29f7cb 4ea686bc
......@@ -896,8 +896,8 @@ running once the system is up.
psmouse.rate= [HW,MOUSE] Set desired mouse report rate, in reports
per second.
psmouse.resetafter=
[HW,MOUSE] Try to reset Synaptics Touchpad after so many
bad packets (0 = never).
[HW,MOUSE] Try to reset the device after so many bad packets
(0 = never).
psmouse.resolution=
[HW,MOUSE] Set desired mouse resolution, in dpi.
psmouse.smartscroll=
......
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)
- 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
- 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
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:
Controller Description Part Number
------------------------------------------------------
/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
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
touchscreen for embedded apps using QTEmbedded, DirectFB, etc. So I feel the
logical choice is to use Linux Imput.
A little info about the MicroTouch USB controller (14-206):
Y is inverted, and the device has a total possible resolution of 0 - 65535.
Y is inverted by the driver by:
input.absmin[ABS_Y] = MTOUCHUSB_MAX_YC;
input.absmax[ABS_Y] = MTOUCHUSB_MIN_YC;
absmin & absmax are also used to scale the data, sine it is rather high
resolution.
---------------touch screen area-----------------
I MicroTouch (xmax,ymax) @I
I X I
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:
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
the controller. This means calibration must be performed within the
userspace.
The controller screen resolution is now 0 to 16384 for both X and Y reporting
the raw touch data. This is the same for the old and new capacitive USB
controllers.
Perhaps at some point an abstract function will be placed into evdev so
generic functions like calibrations, resets, and vendor information can be
requested from the userspace (And the drivers would handle the vendor specific
tasks).
ADDITIONAL INFORMATION/UPDATES/X CONFIGURATION EXAMPLE:
http://groomlakelabs.com/grandamp/code/microtouch/
TODO:
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:
......@@ -83,3 +70,7 @@ this driver! If you want touch drivers only supported within X, please go to:
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
module will be called mousedev.
config INPUT_MOUSEDEV_PSAUX
bool "Provide legacy /dev/psaux device" if EMBEDDED
bool "Provide legacy /dev/psaux device"
default y
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
int "Horizontal screen resolution"
......
......@@ -58,6 +58,9 @@
#include <linux/serio.h>
#include <linux/init.h>
MODULE_DESCRIPTION("Handykey Twiddler keyboard as a joystick driver");
MODULE_LICENSE("GPL");
/*
* Constants.
*/
......@@ -142,7 +145,7 @@ static void twidjoy_process_packet(struct twidjoy *twidjoy, struct pt_regs *regs
* packet processing routine.
*/
static void twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struc pt_regs *regs)
static irqreturn_t twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs)
{
struct twidjoy *twidjoy = serio->private;
......@@ -153,7 +156,7 @@ static void twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned
if ((data & 0x80) == 0)
twidjoy->idx = 0; /* this byte starts a new packet */
else if (twidjoy->idx == 0)
return; /* wrong MSB -- ignore this byte */
return IRQ_HANDLED; /* wrong MSB -- ignore this byte */
if (twidjoy->idx < TWIDJOY_MAX_LENGTH)
twidjoy->data[twidjoy->idx++] = data;
......@@ -163,7 +166,7 @@ static void twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned
twidjoy->idx = 0;
}
return;
return IRQ_HANDLED;
}
/*
......
......@@ -109,7 +109,7 @@ struct kbd98 {
struct jis_kbd_conv jis[16];
};
void kbd98_interrupt(struct serio *serio, unsigned char data,
irqreturn_t kbd98_interrupt(struct serio *serio, unsigned char data,
unsigned int flags, struct pt_regs *regs)
{
struct kbd98 *kbd98 = serio->private;
......@@ -119,15 +119,15 @@ void kbd98_interrupt(struct serio *serio, unsigned char data,
switch (data) {
case KBD98_RET_ACK:
kbd98->ack = 1;
return;
goto out;
case KBD98_RET_NAK:
kbd98->ack = -1;
return;
goto out;
}
if (kbd98->cmdcnt) {
kbd98->cmdbuf[--kbd98->cmdcnt] = data;
return;
goto out;
}
scancode = data & KBD98_KEY;
......@@ -164,7 +164,7 @@ void kbd98_interrupt(struct serio *serio, unsigned char data,
keycode = kbd98->jis[i].emul[kbd98->shift].keycode;
if (keycode == KBD98_KEY_NULL)
return;
break;
if (press) {
kbd98->emul.scancode = scancode;
......@@ -187,27 +187,31 @@ void kbd98_interrupt(struct serio *serio, unsigned char data,
}
input_sync(&kbd98->dev);
return;
break;
case KEY_CAPSLOCK:
input_report_key(&kbd98->dev, keycode, 1);
input_sync(&kbd98->dev);
input_report_key(&kbd98->dev, keycode, 0);
input_sync(&kbd98->dev);
return;
break;
case KBD98_KEY_NULL:
return;
break;
case 0:
printk(KERN_WARNING "kbd98.c: Unknown key (scancode %#x) %s.\n",
data & KBD98_KEY, data & KBD98_RELEASE ? "released" : "pressed");
return;
break;
default:
input_report_key(&kbd98->dev, keycode, press);
input_sync(&kbd98->dev);
break;
}
out:
return IRQ_HANDLED;
}
/*
......
......@@ -26,7 +26,6 @@
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/workqueue.h>
#include <linux/timer.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("AT and PS/2 keyboard driver");
......@@ -173,22 +172,24 @@ struct atkbd {
unsigned char keycode[512];
struct input_dev dev;
struct serio *serio;
struct timer_list timer;
char name[64];
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 cmdcnt;
unsigned char set;
unsigned char extra;
unsigned char release;
int lastkey;
volatile signed char ack;
unsigned char emul;
unsigned short id;
unsigned char write;
unsigned char translated;
unsigned char resend;
unsigned char bat_xl;
unsigned int resend:1;
unsigned int release:1;
unsigned int bat_xl:1;
unsigned int enabled:1;
unsigned int last;
unsigned long time;
};
......@@ -248,6 +249,9 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
goto out;
}
if (!atkbd->enabled)
goto out;
if (atkbd->translated) {
if (atkbd->emul ||
......@@ -300,15 +304,20 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
case ATKBD_KEY_NULL:
break;
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->translated ? "translated" : "raw",
atkbd->set, code, serio->phys);
if (atkbd->translated && atkbd->set == 2 && code == 0x7a)
printk(KERN_WARNING "atkbd.c: This is an XFree86 bug. It shouldn't access"
" hardware directly.\n");
else
printk(KERN_WARNING "atkbd.c: Use 'setkeycodes %s%02x <keycode>' to make it known.\n", code & 0x80 ? "e0" : "", code & 0x7f);
printk(KERN_WARNING "atkbd.c: Use 'setkeycodes %s%02x <keycode>' "
"to make it known.\n",
code & 0x80 ? "e0" : "", code & 0x7f);
}
break;
case ATKBD_SCR_1:
scroll = 1 - atkbd->release * 2;
......@@ -745,6 +754,8 @@ 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");
......
......@@ -14,6 +14,25 @@
#include "psmouse.h"
#include "logips2pp.h"
/* Logitech mouse types */
#define PS2PP_KIND_WHEEL 1
#define PS2PP_KIND_MX 2
#define PS2PP_KIND_TP3 3
/* Logitech mouse features */
#define PS2PP_WHEEL 0x01
#define PS2PP_HWHEEL 0x02
#define PS2PP_SIDE_BTN 0x04
#define PS2PP_EXTRA_BTN 0x08
#define PS2PP_TASK_BTN 0x10
#define PS2PP_NAV_BTN 0x20
struct ps2pp_info {
const int model;
unsigned const int kind;
unsigned const int features;
};
/*
* Process a PS2++ or PS2T++ packet.
*/
......@@ -63,7 +82,6 @@ void ps2pp_process_packet(struct psmouse *psmouse)
packet[0] &= 0x0f;
packet[1] = 0;
packet[2] = 0;
}
}
......@@ -76,18 +94,9 @@ void ps2pp_process_packet(struct psmouse *psmouse)
static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned char command)
{
unsigned char d;
int i;
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11))
if (psmouse_sliced_command(psmouse, command))
return -1;
for (i = 6; i >= 0; i -= 2) {
d = (command >> i) & 3;
if(psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES))
return -1;
}
if (psmouse_command(psmouse, param, PSMOUSE_CMD_POLL))
return -1;
......@@ -113,14 +122,11 @@ static void ps2pp_set_smartscroll(struct psmouse *psmouse)
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
if (psmouse_smartscroll == 1)
param[0] = 1;
else
if (psmouse_smartscroll > 2)
return;
/* else leave param[0] == 0 to disable */
if (psmouse_smartscroll < 2) {
/* 0 - disabled, 1 - enabled */
param[0] = psmouse_smartscroll;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
}
}
/*
......@@ -138,133 +144,167 @@ void ps2pp_set_800dpi(struct psmouse *psmouse)
psmouse_command(psmouse, &param, PSMOUSE_CMD_SETRES);
}
/*
* Detect the exact model and features of a PS2++ or PS2T++ Logitech mouse or
* touchpad.
*/
static int ps2pp_detect_model(struct psmouse *psmouse, unsigned char *param)
static struct ps2pp_info *get_model_info(unsigned char model)
{
int i;
static struct _logips2_list {
const int model;
unsigned const int features;
} logips2pp_list [] = {
{ 12, PS2PP_4BTN},
{ 13, 0 },
{ 40, PS2PP_4BTN },
{ 41, PS2PP_4BTN },
{ 42, PS2PP_4BTN },
{ 43, PS2PP_4BTN },
{ 50, 0 },
{ 51, 0 },
{ 52, PS2PP_4BTN | PS2PP_WHEEL },
{ 53, PS2PP_WHEEL },
{ 61, PS2PP_WHEEL | PS2PP_MX }, /* MX700 */
{ 73, PS2PP_4BTN },
{ 75, PS2PP_WHEEL },
{ 76, PS2PP_WHEEL },
{ 80, PS2PP_4BTN | PS2PP_WHEEL },
{ 81, PS2PP_WHEEL },
{ 83, PS2PP_WHEEL },
{ 88, PS2PP_WHEEL },
{ 96, 0 },
{ 97, 0 },
{ 100 , PS2PP_WHEEL | PS2PP_MX }, /* MX510 */
{ 112 , PS2PP_WHEEL | PS2PP_MX }, /* MX500 */
{ 114 , PS2PP_WHEEL | PS2PP_MX | PS2PP_MX310 }, /* MX310 */
static struct ps2pp_info ps2pp_list[] = {
{ 12, 0, PS2PP_SIDE_BTN},
{ 13, 0, 0 },
{ 40, 0, PS2PP_SIDE_BTN },
{ 41, 0, PS2PP_SIDE_BTN },
{ 42, 0, PS2PP_SIDE_BTN },
{ 43, 0, PS2PP_SIDE_BTN },
{ 50, 0, 0 },
{ 51, 0, 0 },
{ 52, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL },
{ 53, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
{ 61, PS2PP_KIND_MX,
PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, /* MX700 */
{ 73, 0, PS2PP_SIDE_BTN },
{ 75, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
{ 76, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
{ 80, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL },
{ 81, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
{ 83, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
{ 88, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
{ 96, 0, 0 },
{ 97, PS2PP_KIND_TP3, PS2PP_WHEEL | PS2PP_HWHEEL },
{ 100, PS2PP_KIND_MX,
PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, /* MX510 */
{ 112, PS2PP_KIND_MX,
PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, /* MX500 */
{ 114, PS2PP_KIND_MX,
PS2PP_WHEEL | PS2PP_SIDE_BTN |
PS2PP_TASK_BTN | PS2PP_EXTRA_BTN }, /* M310 */
{ }
};
int i;
psmouse->vendor = "Logitech";
psmouse->model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78);
if (param[1] < 3)
clear_bit(BTN_MIDDLE, psmouse->dev.keybit);
if (param[1] < 2)
clear_bit(BTN_RIGHT, psmouse->dev.keybit);
for (i = 0; ps2pp_list[i].model; i++)
if (model == ps2pp_list[i].model)
return &ps2pp_list[i];
return NULL;
}
psmouse->type = PSMOUSE_PS2;
/*
* Set up input device's properties based on the detected mouse model.
*/
for (i = 0; logips2pp_list[i].model; i++){
if (logips2pp_list[i].model == psmouse->model){
psmouse->type = PSMOUSE_PS2PP;
if (logips2pp_list[i].features & PS2PP_4BTN)
static void ps2pp_set_model_properties(struct psmouse *psmouse, struct ps2pp_info *model_info)
{
if (model_info->features & PS2PP_SIDE_BTN)
set_bit(BTN_SIDE, psmouse->dev.keybit);
if (logips2pp_list[i].features & PS2PP_WHEEL){
set_bit(REL_WHEEL, psmouse->dev.relbit);
psmouse->name = "Wheel Mouse";
}
if (logips2pp_list[i].features & PS2PP_MX) {
set_bit(BTN_SIDE, psmouse->dev.keybit);
if (model_info->features & PS2PP_EXTRA_BTN)
set_bit(BTN_EXTRA, psmouse->dev.keybit);
if (model_info->features & PS2PP_TASK_BTN)
set_bit(BTN_TASK, psmouse->dev.keybit);
if (!(logips2pp_list[i].features & PS2PP_MX310)){
set_bit(BTN_BACK, psmouse->dev.keybit);
if (model_info->features & PS2PP_NAV_BTN) {
set_bit(BTN_FORWARD, psmouse->dev.keybit);
set_bit(BTN_BACK, psmouse->dev.keybit);
}
if (model_info->features & PS2PP_WHEEL)
set_bit(REL_WHEEL, psmouse->dev.relbit);
if (model_info->features & PS2PP_HWHEEL)
set_bit(REL_HWHEEL, psmouse->dev.relbit);
switch (model_info->kind) {
case PS2PP_KIND_WHEEL:
psmouse->name = "Wheel Mouse";
break;
case PS2PP_KIND_MX:
psmouse->name = "MX Mouse";
}
break;
case PS2PP_KIND_TP3:
psmouse->name = "TouchPad 3";
break;
}
}
}
/*
* Do Logitech PS2++ / PS2T++ magic init.
* Logitech magic init. Detect whether the mouse is a Logitech one
* and its exact model and try turning on extended protocol for ones
* that support it.
*/
if (psmouse->type == PSMOUSE_PS2PP) {
if (psmouse->model == 97) { /* TouchPad 3 */
int ps2pp_init(struct psmouse *psmouse, int set_properties)
{
unsigned char param[4];
unsigned char protocol = PSMOUSE_PS2;
unsigned char model, buttons;
struct ps2pp_info *model_info;
set_bit(REL_WHEEL, psmouse->dev.relbit);
set_bit(REL_HWHEEL, psmouse->dev.relbit);
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);
if (param[1] != 0) {
model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78);
buttons = param[1];
model_info = get_model_info(model);
param[0] = 0x11; param[1] = 0x04; param[2] = 0x68; /* Unprotect RAM */
/*
* Do Logitech PS2++ / PS2T++ magic init.
*/
if (model == 97) { /* Touch Pad 3 */
/* Unprotect RAM */
param[0] = 0x11; param[1] = 0x04; param[2] = 0x68;
psmouse_command(psmouse, param, 0x30d1);
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);
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);
param[0] = 0;
if (!psmouse_command(psmouse, param, 0x13d1) &&
param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) {
psmouse->name = "TouchPad 3";
return PSMOUSE_PS2TPP;
protocol = PSMOUSE_PS2TPP;
}
} else {
} else if (get_model_info(model) != NULL) {
param[0] = param[1] = param[2] = 0;
ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */
ps2pp_cmd(psmouse, param, 0xDB);
if ((param[0] & 0x78) == 0x48 && (param[1] & 0xf3) == 0xc2 &&
(param[2] & 3) == ((param[1] >> 2) & 3)) {
if ((param[0] & 0x78) == 0x48 &&
(param[1] & 0xf3) == 0xc2 &&
(param[2] & 0x03) == ((param[1] >> 2) & 3)) {
ps2pp_set_smartscroll(psmouse);
return PSMOUSE_PS2PP;
}
protocol = PSMOUSE_PS2PP;
}
}
return 0;
}
if (set_properties) {
psmouse->vendor = "Logitech";
psmouse->model = model;
/*
* Logitech magic init.
*/
int ps2pp_detect(struct psmouse *psmouse)
{
unsigned char param[4];
if (buttons < 3)
clear_bit(BTN_MIDDLE, psmouse->dev.keybit);
if (buttons < 2)
clear_bit(BTN_RIGHT, psmouse->dev.keybit);
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);
if (model_info)
ps2pp_set_model_properties(psmouse, model_info);
}
}
return param[1] != 0 ? ps2pp_detect_model(psmouse, param) : 0;
return protocol;
}
......@@ -11,13 +11,8 @@
#ifndef _LOGIPS2PP_H
#define _LOGIPS2PP_H
#define PS2PP_4BTN 0x01
#define PS2PP_WHEEL 0x02
#define PS2PP_MX 0x04
#define PS2PP_MX310 0x08
struct psmouse;
void ps2pp_process_packet(struct psmouse *psmouse);
void ps2pp_set_800dpi(struct psmouse *psmouse);
int ps2pp_detect(struct psmouse *psmouse);
int ps2pp_init(struct psmouse *psmouse, int set_properties);
#endif
......@@ -43,9 +43,9 @@ int psmouse_smartscroll = 1;
module_param_named(smartscroll, psmouse_smartscroll, bool, 0);
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_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_resolution=");
......@@ -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"};
/*
* psmouse_process_packet() analyzes the PS/2 mouse packet contents and
* reports relevant events to the input module.
* psmouse_process_byte() analyzes the PS/2 data stream and reports
* 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;
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);
/*
......@@ -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_sync(dev);
return PSMOUSE_FULL_PACKET;
}
/*
......@@ -123,6 +132,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
unsigned char data, unsigned int flags, struct pt_regs *regs)
{
struct psmouse *psmouse = serio->private;
psmouse_ret_t rc;
if (psmouse->state == PSMOUSE_IGNORE)
goto out;
......@@ -180,7 +190,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
if (psmouse->pktcnt == 2) {
if (psmouse->packet[1] == PSMOUSE_RET_ID) {
psmouse->state = PSMOUSE_IGNORE;
serio_rescan(serio);
serio_reconnect(serio);
goto out;
}
if (psmouse->type == PSMOUSE_SYNAPTICS) {
......@@ -193,19 +203,32 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
}
}
if (psmouse->type == PSMOUSE_SYNAPTICS) {
/*
* The synaptics driver has its own resync logic,
* so it needs to receive all bytes one at a time.
*/
synaptics_process_byte(psmouse, regs);
goto out;
rc = psmouse->protocol_handler(psmouse, regs);
switch (rc) {
case PSMOUSE_BAD_DATA:
printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n",
psmouse->name, psmouse->phys, psmouse->pktcnt);
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)) {
psmouse_process_packet(psmouse, regs);
case PSMOUSE_FULL_PACKET:
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:
return IRQ_HANDLED;
......@@ -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.
*/
......@@ -363,31 +410,31 @@ static int im_explorer_detect(struct psmouse *psmouse)
* 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;
psmouse->vendor = "Generic";
psmouse->name = "Mouse";
psmouse->model = 0;
/*
* Try Synaptics TouchPad
*/
if (psmouse_max_proto > PSMOUSE_PS2 && synaptics_detect(psmouse)) {
if (max_proto > PSMOUSE_PS2 && synaptics_detect(psmouse)) {
synaptics_hardware = 1;
if (set_properties) {
psmouse->vendor = "Synaptics";
psmouse->name = "TouchPad";
}
if (psmouse_max_proto > PSMOUSE_IMEX) {
if (synaptics_init(psmouse) == 0)
if (max_proto > PSMOUSE_IMEX) {
if (!set_properties || synaptics_init(psmouse) == 0)
return PSMOUSE_SYNAPTICS;
/*
* Some Synaptics touchpads can emulate extended protocols (like IMPS/2).
* Unfortunately Logitech/Genius probes confuse some firmware versions so
* 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
......@@ -395,35 +442,45 @@ static int psmouse_extensions(struct psmouse *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_SIDE, psmouse->dev.keybit);
set_bit(REL_WHEEL, psmouse->dev.relbit);
psmouse->vendor = "Genius";
psmouse->name = "Wheel Mouse";
}
return PSMOUSE_GENPS;
}
if (psmouse_max_proto > PSMOUSE_IMEX) {
int type = ps2pp_detect(psmouse);
if (type)
if (max_proto > PSMOUSE_IMEX) {
int type = ps2pp_init(psmouse, set_properties);
if (type > PSMOUSE_PS2)
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);
if (!psmouse->name)
psmouse->name = "Wheel Mouse";
}
if (max_proto >= PSMOUSE_IMEX && im_explorer_detect(psmouse)) {
if (psmouse_max_proto >= PSMOUSE_IMEX &&
im_explorer_detect(psmouse)) {
if (!set_properties) {
set_bit(BTN_SIDE, psmouse->dev.keybit);
set_bit(BTN_EXTRA, psmouse->dev.keybit);
if (!psmouse->name)
psmouse->name = "Explorer Mouse";
}
return PSMOUSE_IMEX;
}
psmouse->name = "Wheel Mouse";
return PSMOUSE_IMPS;
}
......@@ -473,12 +530,7 @@ static int psmouse_probe(struct psmouse *psmouse)
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS))
printk(KERN_WARNING "psmouse.c: Failed to reset mouse on %s\n", psmouse->serio->phys);
/*
* 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);
return 0;
}
/*
......@@ -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.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
psmouse->state = PSMOUSE_CMD_MODE;
psmouse->serio = serio;
psmouse->dev.private = psmouse;
......@@ -628,13 +679,21 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
return;
}
if (psmouse_probe(psmouse) <= 0) {
if (psmouse_probe(psmouse) < 0) {
serio_close(serio);
kfree(psmouse);
serio->private = NULL;
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",
psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name);
sprintf(psmouse->phys, "%s/input0",
......@@ -668,27 +727,24 @@ static int psmouse_reconnect(struct serio *serio)
{
struct psmouse *psmouse = serio->private;
struct serio_dev *dev = serio->dev;
int old_type;
if (!dev || !psmouse) {
printk(KERN_DEBUG "psmouse: reconnect request, but serio is disconnected, ignoring...\n");
return -1;
}
old_type = psmouse->type;
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(psmouse))
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;
/* ok, the device type (and capabilities) match the old one,
* we can continue using it, complete intialization
*/
psmouse->type = old_type;
psmouse_initialize(psmouse);
if (psmouse->ptport) {
......
......@@ -22,6 +22,13 @@
#define PSMOUSE_ACTIVATED 1
#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_ptport {
......@@ -45,6 +52,7 @@ struct psmouse {
unsigned char type;
unsigned char model;
unsigned long last;
unsigned long out_of_sync;
unsigned char state;
char acking;
volatile char ack;
......@@ -52,6 +60,7 @@ struct psmouse {
char devname[64];
char phys[32];
psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs);
int (*reconnect)(struct psmouse *psmouse);
void (*disconnect)(struct psmouse *psmouse);
};
......@@ -65,10 +74,10 @@ struct psmouse {
#define PSMOUSE_SYNAPTICS 7
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);
extern int psmouse_smartscroll;
extern unsigned int psmouse_rate;
extern unsigned int psmouse_resetafter;
#endif /* _PSMOUSE_H */
This diff is collapsed.
......@@ -9,7 +9,6 @@
#ifndef _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_init(struct psmouse *psmouse);
extern void synaptics_reset(struct psmouse *psmouse);
......@@ -44,13 +43,14 @@ extern void synaptics_reset(struct psmouse *psmouse);
/* synaptics capability bits */
#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_SLEEP(c) ((c) & (1 << 4))
#define SYN_CAP_FOUR_BUTTON(c) ((c) & (1 << 3))
#define SYN_CAP_MULTIFINGER(c) ((c) & (1 << 1))
#define SYN_CAP_PALMDETECT(c) ((c) & (1 << 0))
#define SYN_CAP_VALID(c) ((((c) & 0x00ff00) >> 8) == 0x47)
#define SYN_EXT_CAP_REQUESTS(c) ((((c) & 0x700000) >> 20) == 1)
#define SYN_EXT_CAP_REQUESTS(c) (((c) & 0x700000) >> 20)
#define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12)
/* synaptics modes query bits */
......@@ -86,18 +86,12 @@ struct synaptics_hw_state {
int y;
int z;
int w;
int left;
int right;
int up;
int down;
int b0;
int b1;
int b2;
int b3;
int b4;
int b5;
int b6;
int b7;
unsigned int left:1;
unsigned int right:1;
unsigned int middle:1;
unsigned int up:1;
unsigned int down:1;
unsigned char ext_buttons;
};
struct synaptics_data {
......@@ -108,7 +102,6 @@ struct synaptics_data {
unsigned long int identity; /* Identification */
/* Data for normal processing */
unsigned int out_of_sync; /* # of packets out of sync */
int old_w; /* Previous w value */
unsigned char pkt_type; /* packet type - old, new, etc */
};
......
......@@ -2,6 +2,7 @@
* Input driver to ExplorerPS/2 device driver module.
*
* Copyright (c) 1999-2002 Vojtech Pavlik
* Copyright (c) 2004 Dmitry Torokhov
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published by
......@@ -47,15 +48,24 @@ static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y;
module_param(yres, uint, 0);
MODULE_PARM_DESC(yres, "Vertical screen resolution");
struct mousedev_motion {
int dx, dy, dz;
};
struct mousedev {
int exist;
int open;
int minor;
int misc;
char name[16];
wait_queue_head_t wait;
struct list_head list;
struct input_handle handle;
struct mousedev_motion packet;
unsigned long buttons;
unsigned int pkt_count;
int old_x[4], old_y[4];
unsigned int touch;
};
struct mousedev_list {
......@@ -63,13 +73,10 @@ struct mousedev_list {
struct mousedev *mousedev;
struct list_head node;
int dx, dy, dz;
int old_x[4], old_y[4];
unsigned long buttons;
signed char ps2[6];
unsigned char ready, buffer, bufsiz;
unsigned char mode, imexseq, impsseq;
unsigned int pkt_count;
unsigned char touch;
};
#define MOUSEDEV_SEQ_LEN 6
......@@ -82,135 +89,157 @@ static struct input_handler mousedev_handler;
static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
static struct mousedev mousedev_mix;
#define fx(i) (list->old_x[(list->pkt_count - (i)) & 03])
#define fy(i) (list->old_y[(list->pkt_count - (i)) & 03])
#define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
#define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03])
static void mousedev_abs_event(struct input_handle *handle, struct mousedev_list *list, unsigned int code, int value)
static void mousedev_touchpad_event(struct mousedev *mousedev, unsigned int code, int value)
{
int size;
int touchpad;
/* Ignore joysticks */
if (test_bit(BTN_TRIGGER, handle->dev->keybit))
return;
touchpad = test_bit(BTN_TOOL_FINGER, handle->dev->keybit);
if (mousedev->touch) {
switch (code) {
case ABS_X:
if (touchpad) {
if (list->touch) {
fx(0) = value;
if (list->pkt_count >= 2)
list->dx = ((fx(0) - fx(1)) / 2 + (fx(1) - fx(2)) / 2) / 8;
}
} else {
size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X];
if (size == 0) size = xres;
list->dx += (value * xres - list->old_x[0]) / size;
list->old_x[0] += list->dx * size;
}
if (mousedev->pkt_count >= 2)
mousedev->packet.dx = ((fx(0) - fx(1)) / 2 + (fx(1) - fx(2)) / 2) / 8;
break;
case ABS_Y:
if (touchpad) {
if (list->touch) {
fy(0) = value;
if (list->pkt_count >= 2)
list->dy = -((fy(0) - fy(1)) / 2 + (fy(1) - fy(2)) / 2) / 8;
}
} else {
size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y];
if (size == 0) size = yres;
list->dy -= (value * yres - list->old_y[0]) / size;
list->old_y[0] -= list->dy * size;
}
if (mousedev->pkt_count >= 2)
mousedev->packet.dy = -((fy(0) - fy(1)) / 2 + (fy(1) - fy(2)) / 2) / 8;
break;
}
}
}
static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, unsigned int code, int value)
{
struct mousedev *mousedevs[3] = { handle->private, &mousedev_mix, NULL };
struct mousedev **mousedev = mousedevs;
struct mousedev_list *list;
int index, wake;
while (*mousedev) {
int size;
wake = 0;
switch (code) {
case ABS_X:
size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
if (size == 0) size = xres;
mousedev->packet.dx = (value * xres - mousedev->old_x[0]) / size;
mousedev->old_x[0] = mousedev->packet.dx * size;
break;
list_for_each_entry(list, &(*mousedev)->list, node)
switch (type) {
case EV_ABS:
mousedev_abs_event(handle, list, code, value);
case ABS_Y:
size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y];
if (size == 0) size = yres;
mousedev->packet.dy = (value * yres - mousedev->old_y[0]) / size;
mousedev->old_y[0] = mousedev->packet.dy * size;
break;
}
}
case EV_REL:
static void mousedev_rel_event(struct mousedev *mousedev, unsigned int code, int value)
{
switch (code) {
case REL_X: list->dx += value; break;
case REL_Y: list->dy -= value; break;
case REL_WHEEL: if (list->mode) list->dz -= value; break;
case REL_X: mousedev->packet.dx += value; break;
case REL_Y: mousedev->packet.dy -= value; break;
case REL_WHEEL: mousedev->packet.dz -= value; break;
}
break;
}
case EV_KEY:
if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) {
/* Handle touchpad data */
list->touch = value;
if (!list->touch)
list->pkt_count = 0;
break;
}
static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int value)
{
int index;
switch (code) {
case BTN_TOUCH:
case BTN_0:
case BTN_FORWARD:
case BTN_LEFT: index = 0; break;
case BTN_4:
case BTN_EXTRA: if (list->mode == 2) { index = 4; break; }
case BTN_STYLUS:
case BTN_1:
case BTN_RIGHT: index = 1; break;
case BTN_3:
case BTN_BACK:
case BTN_SIDE: if (list->mode == 2) { index = 3; break; }
case BTN_2:
case BTN_STYLUS2:
case BTN_MIDDLE: index = 2; break;
case BTN_3:
case BTN_BACK:
case BTN_SIDE: index = 3; break;
case BTN_4:
case BTN_EXTRA: index = 4; break;
default: return;
}
switch (value) {
case 0: clear_bit(index, &list->buttons); break;
case 1: set_bit(index, &list->buttons); break;
case 2: return;
}
break;
case EV_SYN:
switch (code) {
case SYN_REPORT:
if (list->touch) {
list->pkt_count++;
/* Input system eats duplicate events,
* but we need all of them to do correct
* averaging so apply present one forward
*/
fx(0) = fx(1);
fy(0) = fy(1);
if (value) {
set_bit(index, &mousedev->buttons);
set_bit(index, &mousedev_mix.buttons);
} else {
clear_bit(index, &mousedev->buttons);
clear_bit(index, &mousedev_mix.buttons);
}
}
static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_motion *packet)
{
struct mousedev_list *list;
list_for_each_entry(list, &mousedev->list, node) {
list->dx += packet->dx;
list->dy += packet->dy;
list->dz += packet->dz;
list->buttons = mousedev->buttons;
list->ready = 1;
kill_fasync(&list->fasync, SIGIO, POLL_IN);
wake = 1;
}
wake_up_interruptible(&mousedev->wait);
}
static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
struct mousedev *mousedev = handle->private;
switch (type) {
case EV_ABS:
/* Ignore joysticks */
if (test_bit(BTN_TRIGGER, handle->dev->keybit))
return;
if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
mousedev_touchpad_event(mousedev, code, value);
else
mousedev_abs_event(handle->dev, mousedev, code, value);
break;
case EV_REL:
mousedev_rel_event(mousedev, code, value);
break;
case EV_KEY:
if (value != 2) {
if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) {
/* Handle touchpad data */
mousedev->touch = value;
if (!mousedev->touch)
mousedev->pkt_count = 0;
}
else
mousedev_key_event(mousedev, code, value);
}
break;
case EV_SYN:
if (code == SYN_REPORT) {
if (mousedev->touch) {
mousedev->pkt_count++;
/* Input system eats duplicate events, but we need all of them
* to do correct averaging so apply present one forward
*/
fx(0) = fx(1);
fy(0) = fy(1);
}
if (wake)
wake_up_interruptible(&((*mousedev)->wait));
mousedev_notify_readers(mousedev, &mousedev->packet);
mousedev_notify_readers(&mousedev_mix, &mousedev->packet);
mousedev++;
memset(&mousedev->packet, 0, sizeof(struct mousedev_motion));
}
break;
}
}
......@@ -326,6 +355,8 @@ static void mousedev_packet(struct mousedev_list *list, unsigned char off)
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);
}
if (list->mode == 1) {
......@@ -391,9 +422,9 @@ static ssize_t mousedev_write(struct file * file, const char * buffer, size_t co
list->impsseq = 0;
list->imexseq = 0;
list->mode = 0;
list->ps2[0] = 0xaa;
list->ps2[1] = 0x00;
list->bufsiz = 2;
list->ps2[1] = 0xaa;
list->ps2[2] = 0x00;
list->bufsiz = 3;
break;
}
......@@ -553,6 +584,7 @@ static struct input_handler mousedev_handler = {
static struct miscdevice psaux_mouse = {
PSMOUSE_MINOR, "psaux", &mousedev_fops
};
static int psaux_registered;
#endif
static int __init mousedev_init(void)
......@@ -572,7 +604,7 @@ static int __init mousedev_init(void)
NULL, "mice");
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
if (!(mousedev_mix.misc = !misc_register(&psaux_mouse)))
if (!(psaux_registered = !misc_register(&psaux_mouse)))
printk(KERN_WARNING "mice: could not misc_register the device\n");
#endif
......@@ -584,7 +616,7 @@ static int __init mousedev_init(void)
static void __exit mousedev_exit(void)
{
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
if (mousedev_mix.misc)
if (psaux_registered)
misc_deregister(&psaux_mouse);
#endif
devfs_remove("input/mice");
......
......@@ -172,3 +172,4 @@ module_exit(power_exit);
MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
MODULE_DESCRIPTION("Input Power Management driver");
MODULE_LICENSE("GPL");
......@@ -51,7 +51,7 @@ spinlock_t kbd98io_lock = SPIN_LOCK_UNLOCKED;
static struct serio kbd98_port;
extern struct pt_regs *kbd_pt_regs;
static void kbd98io_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static irqreturn_t kbd98io_interrupt(int irq, void *dev_id, struct pt_regs *regs);
/*
* kbd98_flush() flushes all data that may be in the keyboard buffers
......@@ -143,7 +143,7 @@ static struct serio kbd98_port =
* to the upper layers.
*/
static void kbd98io_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static irqreturn_t kbd98io_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned long flags;
unsigned char data;
......@@ -154,6 +154,7 @@ static void kbd98io_interrupt(int irq, void *dev_id, struct pt_regs *regs)
spin_unlock_irqrestore(&kbd98io_lock, flags);
serio_interrupt(&kbd98_port, data, 0, regs);
return IRQ_HANDLED;
}
int __init kbd98io_init(void)
......
......@@ -2,6 +2,7 @@
* i8042 keyboard and mouse controller driver for Linux
*
* Copyright (c) 1999-2002 Vojtech Pavlik
* Copyright (c) 2004 Dmitry Torokhov
*/
/*
......@@ -74,6 +75,14 @@ struct i8042_values {
unsigned char *phys;
};
#define I8042_QUEUE_LEN 64
struct {
unsigned char str[I8042_QUEUE_LEN];
unsigned char data[I8042_QUEUE_LEN];
unsigned int read_pos;
unsigned int write_pos;
} i8042_buf;
static struct serio i8042_kbd_port;
static struct serio i8042_aux_port;
static unsigned char i8042_initial_ctr;
......@@ -82,7 +91,7 @@ static unsigned char i8042_mux_open;
static unsigned char i8042_mux_present;
static unsigned char i8042_sysdev_initialized;
static struct pm_dev *i8042_pm_dev;
struct timer_list i8042_timer;
static struct timer_list i8042_timer;
/*
* Shared IRQ's require a device pointer, but this driver doesn't support
......@@ -374,31 +383,28 @@ static char i8042_mux_short[4][16];
static char i8042_mux_phys[4][32];
/*
* i8042_interrupt() is the most important function in this driver -
* it handles the interrupts from the i8042, and sends incoming bytes
* to the upper layers.
* i8042_handle_data() is the most important function in this driver -
* it processes data received by i8042_interrupt and sends it to the
* upper layers.
*/
static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static void i8042_handle_data(unsigned long notused)
{
unsigned long flags;
unsigned char str, data = 0;
unsigned int dfl;
int ret;
mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
/*
* No locking it required on i8042_buf as the tasklet is guaranteed
* to be serialized and if write_pos changes while comparing it with
* read_pos another run will be scheduled by i8042_interrupt.
*/
while (i8042_buf.read_pos != i8042_buf.write_pos) {
spin_lock_irqsave(&i8042_lock, flags);
str = i8042_read_status();
if (str & I8042_STR_OBF)
data = i8042_read_data();
spin_unlock_irqrestore(&i8042_lock, flags);
str = i8042_buf.str[i8042_buf.read_pos];
data = i8042_buf.data[i8042_buf.read_pos];
if (~str & I8042_STR_OBF) {
if (irq) dbg("Interrupt %d, without any data", irq);
ret = 0;
goto out;
}
i8042_buf.read_pos++;
i8042_buf.read_pos %= I8042_QUEUE_LEN;
dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) |
((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0);
......@@ -419,32 +425,67 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs)
dfl & SERIO_PARITY ? ", bad parity" : "",
dfl & SERIO_TIMEOUT ? ", timeout" : "");
serio_interrupt(i8042_mux_port + ((str >> 6) & 3), data, dfl, regs);
goto irq_ret;
}
serio_interrupt(i8042_mux_port + ((str >> 6) & 3), data, dfl, NULL);
} else {
dbg("%02x <- i8042 (interrupt, %s, %d%s%s)",
data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", irq,
dfl & SERIO_PARITY ? ", bad parity" : "",
dfl & SERIO_TIMEOUT ? ", timeout" : "");
if (i8042_aux_values.exists && (str & I8042_STR_AUXDATA)) {
serio_interrupt(&i8042_aux_port, data, dfl, regs);
goto irq_ret;
if (i8042_aux_values.exists && (str & I8042_STR_AUXDATA))
serio_interrupt(&i8042_aux_port, data, dfl, NULL);
else if (i8042_kbd_values.exists)
serio_interrupt(&i8042_kbd_port, data, dfl, NULL);
}
}
}
DECLARE_TASKLET(i8042_tasklet, i8042_handle_data, 0);
/*
* i8042_interrupt() handles the interrupts from i8042 and schedules
* i8042_handle_data to process and pass received bytes to the upper
* layers.
*/
static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned long flags;
unsigned char str;
unsigned int n_bytes = 0;
mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
spin_lock_irqsave(&i8042_lock, flags);
while ((str = i8042_read_status()) & I8042_STR_OBF) {
n_bytes++;
i8042_buf.str[i8042_buf.write_pos] = str;
i8042_buf.data[i8042_buf.write_pos] = i8042_read_data();
i8042_buf.write_pos++;
i8042_buf.write_pos %= I8042_QUEUE_LEN;
if (unlikely(i8042_buf.write_pos == i8042_buf.read_pos))
printk(KERN_WARNING "i8042.c: ring buffer full\n");
}
if (!i8042_kbd_values.exists)
goto irq_ret;
spin_unlock_irqrestore(&i8042_lock, flags);
if (unlikely(n_bytes == 0)) {
if (irq) dbg("Interrupt %d, without any data", irq);
return IRQ_NONE;
}
serio_interrupt(&i8042_kbd_port, data, dfl, regs);
tasklet_schedule(&i8042_tasklet);
irq_ret:
ret = 1;
out:
return IRQ_RETVAL(ret);
return IRQ_HANDLED;
}
/*
* i8042_enable_mux_mode checks whether the controller has an active
* multiplexor and puts the chip into Multiplexed (as opposed to
......@@ -474,8 +515,17 @@ static int i8042_enable_mux_mode(struct i8042_values *values, unsigned char *mux
if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0xa9)
return -1;
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;
}
if (mux_version)
*mux_version = ~param;
......@@ -532,8 +582,8 @@ static int __init i8042_check_mux(struct i8042_values *values)
return -1;
/* Workaround for broken chips which seem to support MUX, but in reality don't. */
/* They all report version 12.10 */
if (mux_version == 0xCA)
/* They all report version 10.12 */
if (mux_version == 0xAC)
return -1;
printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n",
......@@ -868,7 +918,7 @@ static int i8042_controller_resume(void)
static int i8042_notify_sys(struct notifier_block *this, unsigned long code,
void *unused)
{
if (code==SYS_DOWN || code==SYS_HALT)
if (code == SYS_DOWN || code == SYS_HALT)
i8042_controller_cleanup();
return NOTIFY_DONE;
}
......@@ -997,8 +1047,6 @@ void __exit i8042_exit(void)
sysdev_class_unregister(&kbc_sysclass);
}
del_timer_sync(&i8042_timer);
i8042_controller_cleanup();
if (i8042_kbd_values.exists)
......@@ -1011,6 +1059,9 @@ void __exit i8042_exit(void)
if (i8042_mux_values[i].exists)
serio_unregister_port(i8042_mux_port + i);
del_timer_sync(&i8042_timer);
tasklet_kill(&i8042_tasklet);
i8042_platform_exit();
}
......
......@@ -86,20 +86,9 @@ static int parkbd_write(struct serio *port, unsigned char c)
return 0;
}
static int parkbd_open(struct serio *port)
{
return 0;
}
static void parkbd_close(struct serio *port)
{
}
static struct serio parkbd_port =
{
.write = parkbd_write,
.open = parkbd_open,
.close = parkbd_close,
.name = parkbd_name,
.phys = parkbd_phys,
};
......
......@@ -47,23 +47,12 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Q40 PS/2 keyboard controller driver");
MODULE_LICENSE("GPL");
static int q40kbd_open(struct serio *port)
{
return 0;
}
static void q40kbd_close(struct serio *port)
{
}
static struct serio q40kbd_port =
{
.type = SERIO_8042,
.name = "Q40 kbd port",
.phys = "Q40",
.write = NULL,
.open = q40kbd_open,
.close = q40kbd_close,
};
static irqreturn_t q40kbd_interrupt(int irq, void *dev_id,
......
......@@ -293,7 +293,7 @@ void serio_unregister_device(struct serio_dev *dev)
int serio_open(struct serio *serio, struct serio_dev *dev)
{
serio->dev = dev;
if (serio->open(serio)) {
if (serio->open && serio->open(serio)) {
serio->dev = NULL;
return -1;
}
......@@ -303,6 +303,7 @@ 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)
{
if (serio->close)
serio->close(serio);
serio->dev = NULL;
}
......
......@@ -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);
}
static int serport_serio_open(struct serio *serio)
{
return 0;
}
static void serport_serio_close(struct serio *serio)
{
struct serport *serport = serio->driver;
......@@ -87,7 +82,6 @@ static int serport_ldisc_open(struct tty_struct *tty)
serport->serio.type = SERIO_RS232;
serport->serio.write = serport_serio_write;
serport->serio.open = serport_serio_open;
serport->serio.close = serport_serio_close;
serport->serio.driver = serport;
......
......@@ -125,11 +125,9 @@ static void gunze_connect(struct serio *serio, struct serio_dev *dev)
init_input_dev(&gunze->dev);
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.absmin[ABS_X] = 96; gunze->dev.absmin[ABS_Y] = 72;
gunze->dev.absmax[ABS_X] = 4000; gunze->dev.absmax[ABS_Y] = 3000;
input_set_abs_params(&gunze->dev, ABS_X, 96, 4000, 0, 0);
input_set_abs_params(&gunze->dev, ABS_Y, 72, 3000, 0, 0);
gunze->serio = serio;
serio->private = gunze;
......
......@@ -45,6 +45,10 @@
#include <asm/arch/hardware.h>
#include <asm/arch/irqs.h>
MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
MODULE_DESCRIPTION("H3600 touchscreen driver");
MODULE_LICENSE("GPL");
/*
* Definitions & global arrays.
*/
......@@ -103,7 +107,7 @@ struct h3600_dev {
char phys[32];
};
static void action_button_handler(int irq, void *dev_id, struct pt_regs *regs)
static irqreturn_t action_button_handler(int irq, void *dev_id, struct pt_regs *regs)
{
int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1;
struct input_dev *dev = (struct input_dev *) dev_id;
......@@ -111,9 +115,11 @@ static void action_button_handler(int irq, void *dev_id, struct pt_regs *regs)
input_regs(dev, regs);
input_report_key(dev, KEY_ENTER, down);
input_sync(dev);
return IRQ_HANDLED;
}
static void npower_button_handler(int irq, void *dev_id, struct pt_regs *regs)
static irqreturn_t npower_button_handler(int irq, void *dev_id, struct pt_regs *regs)
{
int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1;
struct input_dev *dev = (struct input_dev *) dev_id;
......@@ -126,6 +132,8 @@ static void npower_button_handler(int irq, void *dev_id, struct pt_regs *regs)
input_report_key(dev, KEY_SUSPEND, 1);
input_report_key(dev, KEY_SUSPEND, down);
input_sync(dev);
return IRQ_HANDLED;
}
#ifdef CONFIG_PM
......@@ -141,7 +149,7 @@ enum flite_pwr {
* h3600_flite_power: enables or disables power to frontlight, using last bright */
unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr)
{
unsigned char brightness = ((pwr==FLITE_PWR_OFF) ? 0:flite_brightness);
unsigned char brightness = (pwr == FLITE_PWR_OFF) ? 0 : flite_brightness;
struct h3600_dev *ts = dev->private;
/* Must be in this order */
......@@ -317,8 +325,8 @@ static int state;
#define STATE_DATA 2 /* state where we decode data */
#define STATE_EOF 3 /* state where we decode checksum or EOF */
static void h3600ts_interrupt(struct serio *serio, unsigned char data,
unsigned int flags)
static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data,
unsigned int flags, struct pt_regs *regs)
{
struct h3600_dev *ts = serio->private;
......@@ -329,7 +337,7 @@ static void h3600ts_interrupt(struct serio *serio, unsigned char data,
case STATE_SOF:
if (data == CHAR_SOF)
state = STATE_ID;
return;
break;
case STATE_ID:
ts->event = (data & 0xf0) >> 4;
ts->len = (data & 0xf);
......@@ -339,7 +347,7 @@ static void h3600ts_interrupt(struct serio *serio, unsigned char data,
break;
}
ts->chksum = data;
state=(ts->len > 0 ) ? STATE_DATA : STATE_EOF;
state = (ts->len > 0) ? STATE_DATA : STATE_EOF;
break;
case STATE_DATA:
ts->chksum += data;
......@@ -349,13 +357,15 @@ static void h3600ts_interrupt(struct serio *serio, unsigned char data,
break;
case STATE_EOF:
state = STATE_SOF;
if (data == CHAR_EOF || data == ts->chksum )
h3600ts_process_packet(ts);
if (data == CHAR_EOF || data == ts->chksum)
h3600ts_process_packet(ts, regs);
break;
default:
printk("Error3\n");
break;
}
return IRQ_HANDLED;
}
/*
......@@ -378,8 +388,8 @@ static void h3600ts_connect(struct serio *serio, struct serio_dev *dev)
init_input_dev(&ts->dev);
/* Device specific stuff */
set_GPIO_IRQ_edge( GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES );
set_GPIO_IRQ_edge( GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE );
set_GPIO_IRQ_edge(GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES);
set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE);
if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
......@@ -397,17 +407,12 @@ static void h3600ts_connect(struct serio *serio, struct serio_dev *dev)
kfree(ts);
return;
}
/* 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.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
ts->dev.ledbit[0] = BIT(LED_SLEEP);
ts->dev.absmin[ABS_X] = 60; ts->dev.absmin[ABS_Y] = 35;
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;
input_set_abs_params(&ts->dev, ABS_X, 60, 985, 0, 0);
input_set_abs_params(&ts->dev, ABS_Y, 35, 1024, 0, 0);
set_bit(KEY_RECORD, ts->dev.keybit);
set_bit(KEY_Q, ts->dev.keybit);
......@@ -422,6 +427,9 @@ static void h3600ts_connect(struct serio *serio, struct serio_dev *dev)
ts->dev.keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH);
ts->dev.keybit[LONG(KEY_SUSPEND)] |= BIT(KEY_SUSPEND);
ts->serio = serio;
serio->private = ts;
sprintf(ts->phys, "%s/input0", serio->phys);
ts->dev.event = h3600ts_event;
......
......@@ -28,6 +28,12 @@
* Complete rewrite using Linux Input in 2.6.3
* 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>
......@@ -45,25 +51,28 @@
#include <linux/init.h>
#include <linux/usb.h>
#define MTOUCHUSB_MIN_XC 0xc8
#define MTOUCHUSB_MAX_XC 0xff78
#define MTOUCHUSB_MIN_XC 0x0
#define MTOUCHUSB_MAX_XC 0x4000
#define MTOUCHUSB_XC_FUZZ 0x0
#define MTOUCHUSB_XC_FLAT 0x0
#define MTOUCHUSB_MIN_YC 0x0
#define MTOUCHUSB_MAX_YC 0xff78
#define MTOUCHUSB_MAX_YC 0x4000
#define MTOUCHUSB_YC_FUZZ 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_GET_XC(data) (data[4]<<8 | data[3])
#define MTOUCHUSB_GET_YC(data) (data[6]<<8 | data[5])
#define MTOUCHUSB_GET_XC(data) (data[8]<<8 | data[7])
#define MTOUCHUSB_GET_YC(data) (data[10]<<8 | data[9])
#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_DESC "Microtouch USB HID Touchscreen Driver"
#define DRIVER_DESC "3M USB Touchscreen Driver"
#define DRIVER_LICENSE "GPL"
struct mtouch_usb {
unsigned char *data;
......@@ -76,11 +85,9 @@ struct mtouch_usb {
char phys[64];
};
static __s32 vendor=-1, product=-1;
static struct usb_device_id mtouchusb_devices [] = {
{ USB_DEVICE(0x0596, 0x0001) }, /* 3M (Formerly MicroTouch) 14-206 */
{ } /* Terminating entry */
{ USB_DEVICE(0x0596, 0x0001) },
{ }
};
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
{
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);
if (!mtouch->data)
......@@ -167,7 +174,7 @@ static void mtouchusb_free_buffers(struct usb_device *udev, struct mtouch_usb *m
dbg("%s - called", __FUNCTION__);
if (mtouch->data)
usb_buffer_free(udev, MTOUCHUSB_REPORT_SIZE_DATA,
usb_buffer_free(udev, MTOUCHUSB_REPORT_DATA_SIZE,
mtouch->data, mtouch->data_dma);
}
......@@ -180,41 +187,8 @@ static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_i
char path[64];
char *buf;
int nRet;
int ix;
char valid_device = 0;
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__);
interface = intf->cur_altsetting;
......@@ -222,11 +196,6 @@ static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_i
dbg("%s - setting endpoint", __FUNCTION__);
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))) {
err("%s - Out of memory.", __FUNCTION__);
return -ENOMEM;
......@@ -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.absfuzz[ABS_X] = MTOUCHUSB_XC_FUZZ;
mtouch->input.absflat[ABS_X] = MTOUCHUSB_XC_FLAT;
mtouch->input.absmin[ABS_Y] = MTOUCHUSB_MAX_YC;
mtouch->input.absmax[ABS_Y] = MTOUCHUSB_MIN_YC;
mtouch->input.absmin[ABS_Y] = MTOUCHUSB_MIN_YC;
mtouch->input.absmax[ABS_Y] = MTOUCHUSB_MAX_YC;
mtouch->input.absfuzz[ABS_Y] = MTOUCHUSB_YC_FUZZ;
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
kfree(buf);
nRet = usb_control_msg(mtouch->udev,
usb_rcvctrlpipe(udev, 0x80),
USB_REQ_GET_CONFIGURATION,
USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
usb_rcvctrlpipe(udev, 0),
MTOUCHUSB_RESET,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1,
0,
0x81,
NULL,
0,
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);
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
mtouch->udev,
usb_rcvintpipe(mtouch->udev, 0x81),
mtouch->data,
MTOUCHUSB_REPORT_SIZE_DATA,
MTOUCHUSB_REPORT_DATA_SIZE,
mtouchusb_irq,
mtouch,
endpoint->bInterval);
......@@ -324,15 +293,15 @@ static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_i
input_register_device(&mtouch->input);
nRet = usb_control_msg(mtouch->udev,
usb_rcvctrlpipe(udev, 0x80),
MTOUCHUSB_ASYC_REPORT,
usb_rcvctrlpipe(udev, 0),
MTOUCHUSB_ASYNC_REPORT,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
MTOUCHUSB_ASYC_REPORT,
MTOUCHUSB_ASYC_REPORT,
1,
1,
NULL,
0,
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);
printk(KERN_INFO "input: %s on %s\n", mtouch->name, path);
......@@ -383,9 +352,3 @@ module_exit(mtouchusb_cleanup);
MODULE_AUTHOR( DRIVER_AUTHOR );
MODULE_DESCRIPTION( DRIVER_DESC );
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 {
#define INPUT_KEYCODE(dev, scancode) ((dev->keycodesize == 1) ? ((u8*)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) \
({ unsigned __old; \
switch (dev->keycodesize) { \
......@@ -915,6 +913,12 @@ struct input_handle {
#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)
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_unregister_device(struct input_dev *);
......@@ -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);
#define input_report_key(a,b,c) input_event(a, EV_KEY, b, !!(c))
#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)
#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)
#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)
static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_KEY, code, !!value);
}
static inline void input_report_rel(struct input_dev *dev, unsigned int code, int value)
{
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;
......
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