Commit 7f93220b authored by Linus Torvalds's avatar Linus Torvalds

Merge master.kernel.org:/pub/scm/linux/kernel/git/dtor/input

parents 2b8dfec8 d39969de
...@@ -549,6 +549,7 @@ running once the system is up. ...@@ -549,6 +549,7 @@ running once the system is up.
keyboard and can not control its state keyboard and can not control its state
(Don't attempt to blink the leds) (Don't attempt to blink the leds)
i8042.noaux [HW] Don't check for auxiliary (== mouse) port i8042.noaux [HW] Don't check for auxiliary (== mouse) port
i8042.nokbd [HW] Don't check/create keyboard port
i8042.nomux [HW] Don't check presence of an active multiplexing i8042.nomux [HW] Don't check presence of an active multiplexing
controller controller
i8042.nopnp [HW] Don't use ACPIPnP / PnPBIOS to discover KBD/AUX i8042.nopnp [HW] Don't use ACPIPnP / PnPBIOS to discover KBD/AUX
......
This diff is collapsed.
...@@ -322,7 +322,7 @@ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -322,7 +322,7 @@ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (t < 0 || t >= dev->keycodemax || !dev->keycodesize) return -EINVAL; if (t < 0 || t >= dev->keycodemax || !dev->keycodesize) return -EINVAL;
if (get_user(v, ip + 1)) return -EFAULT; if (get_user(v, ip + 1)) return -EFAULT;
if (v < 0 || v > KEY_MAX) return -EINVAL; if (v < 0 || v > KEY_MAX) return -EINVAL;
if (v >> (dev->keycodesize * 8)) return -EINVAL; if (dev->keycodesize < sizeof(v) && (v >> (dev->keycodesize * 8))) return -EINVAL;
u = SET_INPUT_KEYCODE(dev, t, v); u = SET_INPUT_KEYCODE(dev, t, v);
clear_bit(u, dev->keybit); clear_bit(u, dev->keybit);
set_bit(v, dev->keybit); set_bit(v, dev->keybit);
......
...@@ -249,9 +249,6 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data, ...@@ -249,9 +249,6 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data,
int iforce_get_id_packet(struct iforce *iforce, char *packet) int iforce_get_id_packet(struct iforce *iforce, char *packet)
{ {
DECLARE_WAITQUEUE(wait, current);
int timeout = HZ; /* 1 second */
switch (iforce->bus) { switch (iforce->bus) {
case IFORCE_USB: case IFORCE_USB:
...@@ -260,22 +257,13 @@ int iforce_get_id_packet(struct iforce *iforce, char *packet) ...@@ -260,22 +257,13 @@ int iforce_get_id_packet(struct iforce *iforce, char *packet)
iforce->cr.bRequest = packet[0]; iforce->cr.bRequest = packet[0];
iforce->ctrl->dev = iforce->usbdev; iforce->ctrl->dev = iforce->usbdev;
set_current_state(TASK_INTERRUPTIBLE); if (usb_submit_urb(iforce->ctrl, GFP_ATOMIC))
add_wait_queue(&iforce->wait, &wait);
if (usb_submit_urb(iforce->ctrl, GFP_ATOMIC)) {
set_current_state(TASK_RUNNING);
remove_wait_queue(&iforce->wait, &wait);
return -1; return -1;
}
while (timeout && iforce->ctrl->status == -EINPROGRESS) wait_event_interruptible_timeout(iforce->wait,
timeout = schedule_timeout(timeout); iforce->ctrl->status != -EINPROGRESS, HZ);
set_current_state(TASK_RUNNING); if (iforce->ctrl->status != -EINPROGRESS) {
remove_wait_queue(&iforce->wait, &wait);
if (!timeout) {
usb_unlink_urb(iforce->ctrl); usb_unlink_urb(iforce->ctrl);
return -1; return -1;
} }
...@@ -290,16 +278,10 @@ int iforce_get_id_packet(struct iforce *iforce, char *packet) ...@@ -290,16 +278,10 @@ int iforce_get_id_packet(struct iforce *iforce, char *packet)
iforce->expect_packet = FF_CMD_QUERY; iforce->expect_packet = FF_CMD_QUERY;
iforce_send_packet(iforce, FF_CMD_QUERY, packet); iforce_send_packet(iforce, FF_CMD_QUERY, packet);
set_current_state(TASK_INTERRUPTIBLE); wait_event_interruptible_timeout(iforce->wait,
add_wait_queue(&iforce->wait, &wait); !iforce->expect_packet, HZ);
while (timeout && iforce->expect_packet)
timeout = schedule_timeout(timeout);
set_current_state(TASK_RUNNING);
remove_wait_queue(&iforce->wait, &wait);
if (!timeout) { if (iforce->expect_packet) {
iforce->expect_packet = 0; iforce->expect_packet = 0;
return -1; return -1;
} }
......
...@@ -95,6 +95,7 @@ static void iforce_usb_irq(struct urb *urb, struct pt_regs *regs) ...@@ -95,6 +95,7 @@ static void iforce_usb_irq(struct urb *urb, struct pt_regs *regs)
goto exit; goto exit;
} }
wake_up(&iforce->wait);
iforce_process_packet(iforce, iforce_process_packet(iforce,
(iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1, regs); (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1, regs);
......
...@@ -208,6 +208,7 @@ struct atkbd { ...@@ -208,6 +208,7 @@ struct atkbd {
unsigned char resend; unsigned char resend;
unsigned char release; unsigned char release;
unsigned char bat_xl; unsigned char bat_xl;
unsigned char err_xl;
unsigned int last; unsigned int last;
unsigned long time; unsigned long time;
}; };
...@@ -296,15 +297,18 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, ...@@ -296,15 +297,18 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
if (atkbd->emul || if (atkbd->emul ||
!(code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1 || !(code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1 ||
code == ATKBD_RET_HANGUEL || code == ATKBD_RET_HANJA || code == ATKBD_RET_HANGUEL || code == ATKBD_RET_HANJA ||
code == ATKBD_RET_ERR || (code == ATKBD_RET_ERR && !atkbd->err_xl) ||
(code == ATKBD_RET_BAT && !atkbd->bat_xl))) { (code == ATKBD_RET_BAT && !atkbd->bat_xl))) {
atkbd->release = code >> 7; atkbd->release = code >> 7;
code &= 0x7f; code &= 0x7f;
} }
if (!atkbd->emul && if (!atkbd->emul) {
(code & 0x7f) == (ATKBD_RET_BAT & 0x7f)) if ((code & 0x7f) == (ATKBD_RET_BAT & 0x7f))
atkbd->bat_xl = !atkbd->release; atkbd->bat_xl = !atkbd->release;
if ((code & 0x7f) == (ATKBD_RET_ERR & 0x7f))
atkbd->err_xl = !atkbd->release;
}
} }
switch (code) { switch (code) {
......
...@@ -44,7 +44,7 @@ MODULE_DESCRIPTION(DRIVER_DESC); ...@@ -44,7 +44,7 @@ MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static unsigned char sunkbd_keycode[128] = { static unsigned char sunkbd_keycode[128] = {
0,128,114,129,115, 59, 60, 68, 61, 87, 62, 88, 63,100, 64, 0, 0,128,114,129,115, 59, 60, 68, 61, 87, 62, 88, 63,100, 64,112,
65, 66, 67, 56,103,119, 99, 70,105,130,131,108,106, 1, 2, 3, 65, 66, 67, 56,103,119, 99, 70,105,130,131,108,106, 1, 2, 3,
4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 41, 14,110,113, 98, 55, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 41, 14,110,113, 98, 55,
116,132, 83,133,102, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 116,132, 83,133,102, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
......
...@@ -15,4 +15,4 @@ obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o ...@@ -15,4 +15,4 @@ obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o
obj-$(CONFIG_MOUSE_HIL) += hil_ptr.o obj-$(CONFIG_MOUSE_HIL) += hil_ptr.o
obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o
psmouse-objs := psmouse-base.o alps.o logips2pp.o synaptics.o lifebook.o psmouse-objs := psmouse-base.o alps.o logips2pp.o synaptics.o lifebook.o trackpoint.o
...@@ -170,7 +170,7 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs) ...@@ -170,7 +170,7 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
input_report_key(dev, BTN_TOOL_FINGER, z > 0); input_report_key(dev, BTN_TOOL_FINGER, z > 0);
if (priv->i->flags & ALPS_WHEEL) if (priv->i->flags & ALPS_WHEEL)
input_report_rel(dev, REL_WHEEL, ((packet[0] >> 4) & 0x07) | ((packet[2] >> 2) & 0x08)); input_report_rel(dev, REL_WHEEL, ((packet[2] << 1) & 0x08) - ((packet[0] >> 4) & 0x07));
if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
input_report_key(dev, BTN_FORWARD, forward); input_report_key(dev, BTN_FORWARD, forward);
......
...@@ -150,12 +150,12 @@ static void ps2pp_set_smartscroll(struct psmouse *psmouse, unsigned int smartscr ...@@ -150,12 +150,12 @@ static void ps2pp_set_smartscroll(struct psmouse *psmouse, unsigned int smartscr
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
} }
static ssize_t psmouse_attr_show_smartscroll(struct psmouse *psmouse, char *buf) static ssize_t ps2pp_attr_show_smartscroll(struct psmouse *psmouse, void *data, char *buf)
{ {
return sprintf(buf, "%d\n", psmouse->smartscroll ? 1 : 0); return sprintf(buf, "%d\n", psmouse->smartscroll ? 1 : 0);
} }
static ssize_t psmouse_attr_set_smartscroll(struct psmouse *psmouse, const char *buf, size_t count) static ssize_t ps2pp_attr_set_smartscroll(struct psmouse *psmouse, void *data, const char *buf, size_t count)
{ {
unsigned long value; unsigned long value;
char *rest; char *rest;
...@@ -169,7 +169,8 @@ static ssize_t psmouse_attr_set_smartscroll(struct psmouse *psmouse, const char ...@@ -169,7 +169,8 @@ static ssize_t psmouse_attr_set_smartscroll(struct psmouse *psmouse, const char
return count; return count;
} }
PSMOUSE_DEFINE_ATTR(smartscroll); PSMOUSE_DEFINE_ATTR(smartscroll, S_IWUSR | S_IRUGO, NULL,
ps2pp_attr_show_smartscroll, ps2pp_attr_set_smartscroll);
/* /*
* Support 800 dpi resolution _only_ if the user wants it (there are good * Support 800 dpi resolution _only_ if the user wants it (there are good
...@@ -194,7 +195,7 @@ static void ps2pp_set_resolution(struct psmouse *psmouse, unsigned int resolutio ...@@ -194,7 +195,7 @@ static void ps2pp_set_resolution(struct psmouse *psmouse, unsigned int resolutio
static void ps2pp_disconnect(struct psmouse *psmouse) static void ps2pp_disconnect(struct psmouse *psmouse)
{ {
device_remove_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll); device_remove_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll.dattr);
} }
static struct ps2pp_info *get_model_info(unsigned char model) static struct ps2pp_info *get_model_info(unsigned char model)
...@@ -222,6 +223,7 @@ static struct ps2pp_info *get_model_info(unsigned char model) ...@@ -222,6 +223,7 @@ static struct ps2pp_info *get_model_info(unsigned char model)
{ 80, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL }, { 80, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL },
{ 81, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, { 81, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
{ 83, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, { 83, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
{ 86, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
{ 88, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, { 88, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
{ 96, 0, 0 }, { 96, 0, 0 },
{ 97, PS2PP_KIND_TP3, PS2PP_WHEEL | PS2PP_HWHEEL }, { 97, PS2PP_KIND_TP3, PS2PP_WHEEL | PS2PP_HWHEEL },
...@@ -379,7 +381,8 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties) ...@@ -379,7 +381,8 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties)
psmouse->set_resolution = ps2pp_set_resolution; psmouse->set_resolution = ps2pp_set_resolution;
psmouse->disconnect = ps2pp_disconnect; psmouse->disconnect = ps2pp_disconnect;
device_create_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll); device_create_file(&psmouse->ps2dev.serio->dev,
&psmouse_attr_smartscroll.dattr);
} }
} }
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "logips2pp.h" #include "logips2pp.h"
#include "alps.h" #include "alps.h"
#include "lifebook.h" #include "lifebook.h"
#include "trackpoint.h"
#define DRIVER_DESC "PS/2 mouse driver" #define DRIVER_DESC "PS/2 mouse driver"
...@@ -57,10 +58,30 @@ static unsigned int psmouse_resetafter; ...@@ -57,10 +58,30 @@ static unsigned int psmouse_resetafter;
module_param_named(resetafter, psmouse_resetafter, uint, 0644); module_param_named(resetafter, psmouse_resetafter, uint, 0644);
MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never)."); MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never).");
PSMOUSE_DEFINE_ATTR(protocol); PSMOUSE_DEFINE_ATTR(protocol, S_IWUSR | S_IRUGO,
PSMOUSE_DEFINE_ATTR(rate); NULL,
PSMOUSE_DEFINE_ATTR(resolution); psmouse_attr_show_protocol, psmouse_attr_set_protocol);
PSMOUSE_DEFINE_ATTR(resetafter); PSMOUSE_DEFINE_ATTR(rate, S_IWUSR | S_IRUGO,
(void *) offsetof(struct psmouse, rate),
psmouse_show_int_attr, psmouse_attr_set_rate);
PSMOUSE_DEFINE_ATTR(resolution, S_IWUSR | S_IRUGO,
(void *) offsetof(struct psmouse, resolution),
psmouse_show_int_attr, psmouse_attr_set_resolution);
PSMOUSE_DEFINE_ATTR(resetafter, S_IWUSR | S_IRUGO,
(void *) offsetof(struct psmouse, resetafter),
psmouse_show_int_attr, psmouse_set_int_attr);
static struct attribute *psmouse_attributes[] = {
&psmouse_attr_protocol.dattr.attr,
&psmouse_attr_rate.dattr.attr,
&psmouse_attr_resolution.dattr.attr,
&psmouse_attr_resetafter.dattr.attr,
NULL
};
static struct attribute_group psmouse_attribute_group = {
.attrs = psmouse_attributes,
};
__obsolete_setup("psmouse_noext"); __obsolete_setup("psmouse_noext");
__obsolete_setup("psmouse_resolution="); __obsolete_setup("psmouse_resolution=");
...@@ -519,6 +540,12 @@ static int psmouse_extensions(struct psmouse *psmouse, ...@@ -519,6 +540,12 @@ static int psmouse_extensions(struct psmouse *psmouse,
if (max_proto >= PSMOUSE_IMPS && intellimouse_detect(psmouse, set_properties) == 0) if (max_proto >= PSMOUSE_IMPS && intellimouse_detect(psmouse, set_properties) == 0)
return PSMOUSE_IMPS; return PSMOUSE_IMPS;
/*
* Try to initialize the IBM TrackPoint
*/
if (max_proto > PSMOUSE_IMEX && trackpoint_detect(psmouse, set_properties) == 0)
return PSMOUSE_TRACKPOINT;
/* /*
* Okay, all failed, we have a standard mouse here. The number of the buttons * Okay, all failed, we have a standard mouse here. The number of the buttons
* is still a question, though. We assume 3. * is still a question, though. We assume 3.
...@@ -599,6 +626,12 @@ static struct psmouse_protocol psmouse_protocols[] = { ...@@ -599,6 +626,12 @@ static struct psmouse_protocol psmouse_protocols[] = {
.alias = "lifebook", .alias = "lifebook",
.init = lifebook_init, .init = lifebook_init,
}, },
{
.type = PSMOUSE_TRACKPOINT,
.name = "TPPS/2",
.alias = "trackpoint",
.detect = trackpoint_detect,
},
{ {
.type = PSMOUSE_AUTO, .type = PSMOUSE_AUTO,
.name = "auto", .name = "auto",
...@@ -787,10 +820,7 @@ static void psmouse_disconnect(struct serio *serio) ...@@ -787,10 +820,7 @@ static void psmouse_disconnect(struct serio *serio)
psmouse = serio_get_drvdata(serio); psmouse = serio_get_drvdata(serio);
device_remove_file(&serio->dev, &psmouse_attr_protocol); sysfs_remove_group(&serio->dev.kobj, &psmouse_attribute_group);
device_remove_file(&serio->dev, &psmouse_attr_rate);
device_remove_file(&serio->dev, &psmouse_attr_resolution);
device_remove_file(&serio->dev, &psmouse_attr_resetafter);
down(&psmouse_sem); down(&psmouse_sem);
...@@ -927,10 +957,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) ...@@ -927,10 +957,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
if (parent && parent->pt_activate) if (parent && parent->pt_activate)
parent->pt_activate(parent); parent->pt_activate(parent);
device_create_file(&serio->dev, &psmouse_attr_protocol); sysfs_create_group(&serio->dev.kobj, &psmouse_attribute_group);
device_create_file(&serio->dev, &psmouse_attr_rate);
device_create_file(&serio->dev, &psmouse_attr_resolution);
device_create_file(&serio->dev, &psmouse_attr_resetafter);
psmouse_activate(psmouse); psmouse_activate(psmouse);
...@@ -1027,10 +1054,12 @@ static struct serio_driver psmouse_drv = { ...@@ -1027,10 +1054,12 @@ static struct serio_driver psmouse_drv = {
.cleanup = psmouse_cleanup, .cleanup = psmouse_cleanup,
}; };
ssize_t psmouse_attr_show_helper(struct device *dev, char *buf, ssize_t psmouse_attr_show_helper(struct device *dev, struct device_attribute *devattr,
ssize_t (*handler)(struct psmouse *, char *)) char *buf)
{ {
struct serio *serio = to_serio_port(dev); struct serio *serio = to_serio_port(dev);
struct psmouse_attribute *attr = to_psmouse_attr(devattr);
struct psmouse *psmouse;
int retval; int retval;
retval = serio_pin_driver(serio); retval = serio_pin_driver(serio);
...@@ -1042,19 +1071,21 @@ ssize_t psmouse_attr_show_helper(struct device *dev, char *buf, ...@@ -1042,19 +1071,21 @@ ssize_t psmouse_attr_show_helper(struct device *dev, char *buf,
goto out; goto out;
} }
retval = handler(serio_get_drvdata(serio), buf); psmouse = serio_get_drvdata(serio);
retval = attr->show(psmouse, attr->data, buf);
out: out:
serio_unpin_driver(serio); serio_unpin_driver(serio);
return retval; return retval;
} }
ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t count, ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *devattr,
ssize_t (*handler)(struct psmouse *, const char *, size_t)) const char *buf, size_t count)
{ {
struct serio *serio = to_serio_port(dev); struct serio *serio = to_serio_port(dev);
struct psmouse *psmouse = serio_get_drvdata(serio); struct psmouse_attribute *attr = to_psmouse_attr(devattr);
struct psmouse *parent = NULL; struct psmouse *psmouse, *parent = NULL;
int retval; int retval;
retval = serio_pin_driver(serio); retval = serio_pin_driver(serio);
...@@ -1070,6 +1101,8 @@ ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t coun ...@@ -1070,6 +1101,8 @@ ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t coun
if (retval) if (retval)
goto out_unpin; goto out_unpin;
psmouse = serio_get_drvdata(serio);
if (psmouse->state == PSMOUSE_IGNORE) { if (psmouse->state == PSMOUSE_IGNORE) {
retval = -ENODEV; retval = -ENODEV;
goto out_up; goto out_up;
...@@ -1082,7 +1115,7 @@ ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t coun ...@@ -1082,7 +1115,7 @@ ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t coun
psmouse_deactivate(psmouse); psmouse_deactivate(psmouse);
retval = handler(psmouse, buf, count); retval = attr->set(psmouse, attr->data, buf, count);
if (retval != -ENODEV) if (retval != -ENODEV)
psmouse_activate(psmouse); psmouse_activate(psmouse);
...@@ -1097,12 +1130,34 @@ ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t coun ...@@ -1097,12 +1130,34 @@ ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t coun
return retval; return retval;
} }
static ssize_t psmouse_attr_show_protocol(struct psmouse *psmouse, char *buf) static ssize_t psmouse_show_int_attr(struct psmouse *psmouse, void *offset, char *buf)
{
unsigned long *field = (unsigned long *)((char *)psmouse + (size_t)offset);
return sprintf(buf, "%lu\n", *field);
}
static ssize_t psmouse_set_int_attr(struct psmouse *psmouse, void *offset, const char *buf, size_t count)
{
unsigned long *field = (unsigned long *)((char *)psmouse + (size_t)offset);
unsigned long value;
char *rest;
value = simple_strtoul(buf, &rest, 10);
if (*rest)
return -EINVAL;
*field = value;
return count;
}
static ssize_t psmouse_attr_show_protocol(struct psmouse *psmouse, void *data, char *buf)
{ {
return sprintf(buf, "%s\n", psmouse_protocol_by_type(psmouse->type)->name); return sprintf(buf, "%s\n", psmouse_protocol_by_type(psmouse->type)->name);
} }
static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, const char *buf, size_t count) static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, const char *buf, size_t count)
{ {
struct serio *serio = psmouse->ps2dev.serio; struct serio *serio = psmouse->ps2dev.serio;
struct psmouse *parent = NULL; struct psmouse *parent = NULL;
...@@ -1166,12 +1221,7 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, const char *bu ...@@ -1166,12 +1221,7 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, const char *bu
return count; return count;
} }
static ssize_t psmouse_attr_show_rate(struct psmouse *psmouse, char *buf) static ssize_t psmouse_attr_set_rate(struct psmouse *psmouse, void *data, const char *buf, size_t count)
{
return sprintf(buf, "%d\n", psmouse->rate);
}
static ssize_t psmouse_attr_set_rate(struct psmouse *psmouse, const char *buf, size_t count)
{ {
unsigned long value; unsigned long value;
char *rest; char *rest;
...@@ -1184,12 +1234,7 @@ static ssize_t psmouse_attr_set_rate(struct psmouse *psmouse, const char *buf, s ...@@ -1184,12 +1234,7 @@ static ssize_t psmouse_attr_set_rate(struct psmouse *psmouse, const char *buf, s
return count; return count;
} }
static ssize_t psmouse_attr_show_resolution(struct psmouse *psmouse, char *buf) static ssize_t psmouse_attr_set_resolution(struct psmouse *psmouse, void *data, const char *buf, size_t count)
{
return sprintf(buf, "%d\n", psmouse->resolution);
}
static ssize_t psmouse_attr_set_resolution(struct psmouse *psmouse, const char *buf, size_t count)
{ {
unsigned long value; unsigned long value;
char *rest; char *rest;
...@@ -1202,23 +1247,6 @@ static ssize_t psmouse_attr_set_resolution(struct psmouse *psmouse, const char * ...@@ -1202,23 +1247,6 @@ static ssize_t psmouse_attr_set_resolution(struct psmouse *psmouse, const char *
return count; return count;
} }
static ssize_t psmouse_attr_show_resetafter(struct psmouse *psmouse, char *buf)
{
return sprintf(buf, "%d\n", psmouse->resetafter);
}
static ssize_t psmouse_attr_set_resetafter(struct psmouse *psmouse, const char *buf, size_t count)
{
unsigned long value;
char *rest;
value = simple_strtoul(buf, &rest, 10);
if (*rest)
return -EINVAL;
psmouse->resetafter = value;
return count;
}
static int psmouse_set_maxproto(const char *val, struct kernel_param *kp) static int psmouse_set_maxproto(const char *val, struct kernel_param *kp)
{ {
...@@ -1234,7 +1262,7 @@ static int psmouse_set_maxproto(const char *val, struct kernel_param *kp) ...@@ -1234,7 +1262,7 @@ static int psmouse_set_maxproto(const char *val, struct kernel_param *kp)
*((unsigned int *)kp->arg) = proto->type; *((unsigned int *)kp->arg) = proto->type;
return 0; \ return 0;
} }
static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp) static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp)
......
...@@ -78,6 +78,7 @@ enum psmouse_type { ...@@ -78,6 +78,7 @@ enum psmouse_type {
PSMOUSE_SYNAPTICS, PSMOUSE_SYNAPTICS,
PSMOUSE_ALPS, PSMOUSE_ALPS,
PSMOUSE_LIFEBOOK, PSMOUSE_LIFEBOOK,
PSMOUSE_TRACKPOINT,
PSMOUSE_AUTO /* This one should always be last */ PSMOUSE_AUTO /* This one should always be last */
}; };
...@@ -85,24 +86,37 @@ int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command); ...@@ -85,24 +86,37 @@ int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command);
int psmouse_reset(struct psmouse *psmouse); int psmouse_reset(struct psmouse *psmouse);
void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution); void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution);
ssize_t psmouse_attr_show_helper(struct device *dev, char *buf,
ssize_t (*handler)(struct psmouse *, char *)); struct psmouse_attribute {
ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t count, struct device_attribute dattr;
ssize_t (*handler)(struct psmouse *, const char *, size_t)); void *data;
ssize_t (*show)(struct psmouse *psmouse, void *data, char *buf);
#define PSMOUSE_DEFINE_ATTR(_name) \ ssize_t (*set)(struct psmouse *psmouse, void *data,
static ssize_t psmouse_attr_show_##_name(struct psmouse *, char *); \ const char *buf, size_t count);
static ssize_t psmouse_attr_set_##_name(struct psmouse *, const char *, size_t);\ };
static ssize_t psmouse_do_show_##_name(struct device *d, struct device_attribute *attr, char *b) \ #define to_psmouse_attr(a) container_of((a), struct psmouse_attribute, dattr)
{ \
return psmouse_attr_show_helper(d, b, psmouse_attr_show_##_name); \ ssize_t psmouse_attr_show_helper(struct device *dev, struct device_attribute *attr,
} \ char *buf);
static ssize_t psmouse_do_set_##_name(struct device *d, struct device_attribute *attr, const char *b, size_t s)\ ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *attr,
{ \ const char *buf, size_t count);
return psmouse_attr_set_helper(d, b, s, psmouse_attr_set_##_name); \
} \ #define PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set) \
static struct device_attribute psmouse_attr_##_name = \ static ssize_t _show(struct psmouse *, void *data, char *); \
__ATTR(_name, S_IWUSR | S_IRUGO, \ static ssize_t _set(struct psmouse *, void *data, const char *, size_t); \
psmouse_do_show_##_name, psmouse_do_set_##_name); static struct psmouse_attribute psmouse_attr_##_name = { \
.dattr = { \
.attr = { \
.name = __stringify(_name), \
.mode = _mode, \
.owner = THIS_MODULE, \
}, \
.show = psmouse_attr_show_helper, \
.store = psmouse_attr_set_helper, \
}, \
.data = _data, \
.show = _show, \
.set = _set, \
}
#endif /* _PSMOUSE_H */ #endif /* _PSMOUSE_H */
/*
* Stephen Evanchik <evanchsa@gmail.com>
*
* 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
* the Free Software Foundation.
*
* Trademarks are the property of their respective owners.
*/
#include <linux/delay.h>
#include <linux/serio.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/input.h>
#include <linux/libps2.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include "psmouse.h"
#include "trackpoint.h"
/*
* Device IO: read, write and toggle bit
*/
static int trackpoint_read(struct ps2dev *ps2dev, unsigned char loc, unsigned char *results)
{
if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) ||
ps2_command(ps2dev, results, MAKE_PS2_CMD(0, 1, loc))) {
return -1;
}
return 0;
}
static int trackpoint_write(struct ps2dev *ps2dev, unsigned char loc, unsigned char val)
{
if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) ||
ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_WRITE_MEM)) ||
ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, loc)) ||
ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, val))) {
return -1;
}
return 0;
}
static int trackpoint_toggle_bit(struct ps2dev *ps2dev, unsigned char loc, unsigned char mask)
{
/* Bad things will happen if the loc param isn't in this range */
if (loc < 0x20 || loc >= 0x2F)
return -1;
if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) ||
ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_TOGGLE)) ||
ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, loc)) ||
ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, mask))) {
return -1;
}
return 0;
}
/*
* Trackpoint-specific attributes
*/
struct trackpoint_attr_data {
size_t field_offset;
unsigned char command;
unsigned char mask;
};
static ssize_t trackpoint_show_int_attr(struct psmouse *psmouse, void *data, char *buf)
{
struct trackpoint_data *tp = psmouse->private;
struct trackpoint_attr_data *attr = data;
unsigned char *field = (unsigned char *)((char *)tp + attr->field_offset);
return sprintf(buf, "%u\n", *field);
}
static ssize_t trackpoint_set_int_attr(struct psmouse *psmouse, void *data,
const char *buf, size_t count)
{
struct trackpoint_data *tp = psmouse->private;
struct trackpoint_attr_data *attr = data;
unsigned char *field = (unsigned char *)((char *)tp + attr->field_offset);
unsigned long value;
char *rest;
value = simple_strtoul(buf, &rest, 10);
if (*rest || value > 255)
return -EINVAL;
*field = value;
trackpoint_write(&psmouse->ps2dev, attr->command, value);
return count;
}
#define TRACKPOINT_INT_ATTR(_name, _command) \
static struct trackpoint_attr_data trackpoint_attr_##_name = { \
.field_offset = offsetof(struct trackpoint_data, _name), \
.command = _command, \
}; \
PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \
&trackpoint_attr_##_name, \
trackpoint_show_int_attr, trackpoint_set_int_attr)
static ssize_t trackpoint_set_bit_attr(struct psmouse *psmouse, void *data,
const char *buf, size_t count)
{
struct trackpoint_data *tp = psmouse->private;
struct trackpoint_attr_data *attr = data;
unsigned char *field = (unsigned char *)((char *)tp + attr->field_offset);
unsigned long value;
char *rest;
value = simple_strtoul(buf, &rest, 10);
if (*rest || value > 1)
return -EINVAL;
if (*field != value) {
*field = value;
trackpoint_toggle_bit(&psmouse->ps2dev, attr->command, attr->mask);
}
return count;
}
#define TRACKPOINT_BIT_ATTR(_name, _command, _mask) \
static struct trackpoint_attr_data trackpoint_attr_##_name = { \
.field_offset = offsetof(struct trackpoint_data, _name), \
.command = _command, \
.mask = _mask, \
}; \
PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \
&trackpoint_attr_##_name, \
trackpoint_show_int_attr, trackpoint_set_bit_attr)
TRACKPOINT_INT_ATTR(sensitivity, TP_SENS);
TRACKPOINT_INT_ATTR(speed, TP_SPEED);
TRACKPOINT_INT_ATTR(inertia, TP_INERTIA);
TRACKPOINT_INT_ATTR(reach, TP_REACH);
TRACKPOINT_INT_ATTR(draghys, TP_DRAGHYS);
TRACKPOINT_INT_ATTR(mindrag, TP_MINDRAG);
TRACKPOINT_INT_ATTR(thresh, TP_THRESH);
TRACKPOINT_INT_ATTR(upthresh, TP_UP_THRESH);
TRACKPOINT_INT_ATTR(ztime, TP_Z_TIME);
TRACKPOINT_INT_ATTR(jenks, TP_JENKS_CURV);
TRACKPOINT_BIT_ATTR(press_to_select, TP_TOGGLE_PTSON, TP_MASK_PTSON);
TRACKPOINT_BIT_ATTR(skipback, TP_TOGGLE_SKIPBACK, TP_MASK_SKIPBACK);
TRACKPOINT_BIT_ATTR(ext_dev, TP_TOGGLE_EXT_DEV, TP_MASK_EXT_DEV);
static struct attribute *trackpoint_attrs[] = {
&psmouse_attr_sensitivity.dattr.attr,
&psmouse_attr_speed.dattr.attr,
&psmouse_attr_inertia.dattr.attr,
&psmouse_attr_reach.dattr.attr,
&psmouse_attr_draghys.dattr.attr,
&psmouse_attr_mindrag.dattr.attr,
&psmouse_attr_thresh.dattr.attr,
&psmouse_attr_upthresh.dattr.attr,
&psmouse_attr_ztime.dattr.attr,
&psmouse_attr_jenks.dattr.attr,
&psmouse_attr_press_to_select.dattr.attr,
&psmouse_attr_skipback.dattr.attr,
&psmouse_attr_ext_dev.dattr.attr,
NULL
};
static struct attribute_group trackpoint_attr_group = {
.attrs = trackpoint_attrs,
};
static void trackpoint_disconnect(struct psmouse *psmouse)
{
sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj, &trackpoint_attr_group);
kfree(psmouse->private);
psmouse->private = NULL;
}
static int trackpoint_sync(struct psmouse *psmouse)
{
unsigned char toggle;
struct trackpoint_data *tp = psmouse->private;
if (!tp)
return -1;
/* Disable features that may make device unusable with this driver */
trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_TWOHAND, &toggle);
if (toggle & TP_MASK_TWOHAND)
trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_TWOHAND, TP_MASK_TWOHAND);
trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_SOURCE_TAG, &toggle);
if (toggle & TP_MASK_SOURCE_TAG)
trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_SOURCE_TAG, TP_MASK_SOURCE_TAG);
trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_MB, &toggle);
if (toggle & TP_MASK_MB)
trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_MB, TP_MASK_MB);
/* Push the config to the device */
trackpoint_write(&psmouse->ps2dev, TP_SENS, tp->sensitivity);
trackpoint_write(&psmouse->ps2dev, TP_INERTIA, tp->inertia);
trackpoint_write(&psmouse->ps2dev, TP_SPEED, tp->speed);
trackpoint_write(&psmouse->ps2dev, TP_REACH, tp->reach);
trackpoint_write(&psmouse->ps2dev, TP_DRAGHYS, tp->draghys);
trackpoint_write(&psmouse->ps2dev, TP_MINDRAG, tp->mindrag);
trackpoint_write(&psmouse->ps2dev, TP_THRESH, tp->thresh);
trackpoint_write(&psmouse->ps2dev, TP_UP_THRESH, tp->upthresh);
trackpoint_write(&psmouse->ps2dev, TP_Z_TIME, tp->ztime);
trackpoint_write(&psmouse->ps2dev, TP_JENKS_CURV, tp->jenks);
trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_PTSON, &toggle);
if (((toggle & TP_MASK_PTSON) == TP_MASK_PTSON) != tp->press_to_select)
trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_PTSON, TP_MASK_PTSON);
trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_SKIPBACK, &toggle);
if (((toggle & TP_MASK_SKIPBACK) == TP_MASK_SKIPBACK) != tp->skipback)
trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_SKIPBACK, TP_MASK_SKIPBACK);
trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_EXT_DEV, &toggle);
if (((toggle & TP_MASK_EXT_DEV) == TP_MASK_EXT_DEV) != tp->ext_dev)
trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_EXT_DEV, TP_MASK_EXT_DEV);
return 0;
}
static void trackpoint_defaults(struct trackpoint_data *tp)
{
tp->press_to_select = TP_DEF_PTSON;
tp->sensitivity = TP_DEF_SENS;
tp->speed = TP_DEF_SPEED;
tp->reach = TP_DEF_REACH;
tp->draghys = TP_DEF_DRAGHYS;
tp->mindrag = TP_DEF_MINDRAG;
tp->thresh = TP_DEF_THRESH;
tp->upthresh = TP_DEF_UP_THRESH;
tp->ztime = TP_DEF_Z_TIME;
tp->jenks = TP_DEF_JENKS_CURV;
tp->inertia = TP_DEF_INERTIA;
tp->skipback = TP_DEF_SKIPBACK;
tp->ext_dev = TP_DEF_EXT_DEV;
}
int trackpoint_detect(struct psmouse *psmouse, int set_properties)
{
struct trackpoint_data *priv;
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char firmware_id;
unsigned char button_info;
unsigned char param[2];
param[0] = param[1] = 0;
if (ps2_command(ps2dev, param, MAKE_PS2_CMD(0, 2, TP_READ_ID)))
return -1;
if (param[0] != TP_MAGIC_IDENT)
return -1;
if (!set_properties)
return 0;
firmware_id = param[1];
if (trackpoint_read(&psmouse->ps2dev, TP_EXT_BTN, &button_info)) {
printk(KERN_WARNING "trackpoint.c: failed to get extended button data\n");
button_info = 0;
}
psmouse->private = priv = kcalloc(1, sizeof(struct trackpoint_data), GFP_KERNEL);
if (!priv)
return -1;
psmouse->vendor = "IBM";
psmouse->name = "TrackPoint";
psmouse->reconnect = trackpoint_sync;
psmouse->disconnect = trackpoint_disconnect;
trackpoint_defaults(priv);
trackpoint_sync(psmouse);
sysfs_create_group(&ps2dev->serio->dev.kobj, &trackpoint_attr_group);
printk(KERN_INFO "IBM TrackPoint firmware: 0x%02x, buttons: %d/%d\n",
firmware_id, (button_info & 0xf0) >> 4, button_info & 0x0f);
return 0;
}
/*
* IBM TrackPoint PS/2 mouse driver
*
* Stephen Evanchik <evanchsa@gmail.com>
*
* 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
* the Free Software Foundation.
*/
#ifndef _TRACKPOINT_H
#define _TRACKPOINT_H
/*
* These constants are from the TrackPoint System
* Engineering documentation Version 4 from IBM Watson
* research:
* http://wwwcssrv.almaden.ibm.com/trackpoint/download.html
*/
#define TP_COMMAND 0xE2 /* Commands start with this */
#define TP_READ_ID 0xE1 /* Sent for device identification */
#define TP_MAGIC_IDENT 0x01 /* Sent after a TP_READ_ID followed */
/* by the firmware ID */
/*
* Commands
*/
#define TP_RECALIB 0x51 /* Recalibrate */
#define TP_POWER_DOWN 0x44 /* Can only be undone through HW reset */
#define TP_EXT_DEV 0x21 /* Determines if external device is connected (RO) */
#define TP_EXT_BTN 0x4B /* Read extended button status */
#define TP_POR 0x7F /* Execute Power on Reset */
#define TP_POR_RESULTS 0x25 /* Read Power on Self test results */
#define TP_DISABLE_EXT 0x40 /* Disable external pointing device */
#define TP_ENABLE_EXT 0x41 /* Enable external pointing device */
/*
* Mode manipulation
*/
#define TP_SET_SOFT_TRANS 0x4E /* Set mode */
#define TP_CANCEL_SOFT_TRANS 0xB9 /* Cancel mode */
#define TP_SET_HARD_TRANS 0x45 /* Mode can only be set */
/*
* Register oriented commands/properties
*/
#define TP_WRITE_MEM 0x81
#define TP_READ_MEM 0x80 /* Not used in this implementation */
/*
* RAM Locations for properties
*/
#define TP_SENS 0x4A /* Sensitivity */
#define TP_MB 0x4C /* Read Middle Button Status (RO) */
#define TP_INERTIA 0x4D /* Negative Inertia */
#define TP_SPEED 0x60 /* Speed of TP Cursor */
#define TP_REACH 0x57 /* Backup for Z-axis press */
#define TP_DRAGHYS 0x58 /* Drag Hysteresis */
/* (how hard it is to drag */
/* with Z-axis pressed) */
#define TP_MINDRAG 0x59 /* Minimum amount of force needed */
/* to trigger dragging */
#define TP_THRESH 0x5C /* Minimum value for a Z-axis press */
#define TP_UP_THRESH 0x5A /* Used to generate a 'click' on Z-axis */
#define TP_Z_TIME 0x5E /* How sharp of a press */
#define TP_JENKS_CURV 0x5D /* Minimum curvature for double click */
/*
* Toggling Flag bits
*/
#define TP_TOGGLE 0x47 /* Toggle command */
#define TP_TOGGLE_MB 0x23 /* Disable/Enable Middle Button */
#define TP_MASK_MB 0x01
#define TP_TOGGLE_EXT_DEV 0x23 /* Toggle external device */
#define TP_MASK_EXT_DEV 0x02
#define TP_TOGGLE_DRIFT 0x23 /* Drift Correction */
#define TP_MASK_DRIFT 0x80
#define TP_TOGGLE_BURST 0x28 /* Burst Mode */
#define TP_MASK_BURST 0x80
#define TP_TOGGLE_PTSON 0x2C /* Press to Select */
#define TP_MASK_PTSON 0x01
#define TP_TOGGLE_HARD_TRANS 0x2C /* Alternate method to set Hard Transparency */
#define TP_MASK_HARD_TRANS 0x80
#define TP_TOGGLE_TWOHAND 0x2D /* Two handed */
#define TP_MASK_TWOHAND 0x01
#define TP_TOGGLE_STICKY_TWO 0x2D /* Sticky two handed */
#define TP_MASK_STICKY_TWO 0x04
#define TP_TOGGLE_SKIPBACK 0x2D /* Suppress movement after drag release */
#define TP_MASK_SKIPBACK 0x08
#define TP_TOGGLE_SOURCE_TAG 0x20 /* Bit 3 of the first packet will be set to
to the origin of the packet (external or TP) */
#define TP_MASK_SOURCE_TAG 0x80
#define TP_TOGGLE_EXT_TAG 0x22 /* Bit 3 of the first packet coming from the
external device will be forced to 1 */
#define TP_MASK_EXT_TAG 0x04
/* Power on Self Test Results */
#define TP_POR_SUCCESS 0x3B
/*
* Default power on values
*/
#define TP_DEF_SENS 0x80
#define TP_DEF_INERTIA 0x06
#define TP_DEF_SPEED 0x61
#define TP_DEF_REACH 0x0A
#define TP_DEF_DRAGHYS 0xFF
#define TP_DEF_MINDRAG 0x14
#define TP_DEF_THRESH 0x08
#define TP_DEF_UP_THRESH 0xFF
#define TP_DEF_Z_TIME 0x26
#define TP_DEF_JENKS_CURV 0x87
/* Toggles */
#define TP_DEF_MB 0x00
#define TP_DEF_PTSON 0x00
#define TP_DEF_SKIPBACK 0x00
#define TP_DEF_EXT_DEV 0x01
#define MAKE_PS2_CMD(params, results, cmd) ((params<<12) | (results<<8) | (cmd))
struct trackpoint_data
{
unsigned char sensitivity, speed, inertia, reach;
unsigned char draghys, mindrag;
unsigned char thresh, upthresh;
unsigned char ztime, jenks;
unsigned char press_to_select;
unsigned char skipback;
unsigned char ext_dev;
};
extern int trackpoint_detect(struct psmouse *psmouse, int set_properties);
#endif /* _TRACKPOINT_H */
...@@ -69,16 +69,16 @@ static inline int i8042_platform_init(void) ...@@ -69,16 +69,16 @@ static inline int i8042_platform_init(void)
*/ */
#if !defined(__sh__) && !defined(__alpha__) && !defined(__mips__) && !defined(CONFIG_PPC64) #if !defined(__sh__) && !defined(__alpha__) && !defined(__mips__) && !defined(CONFIG_PPC64)
if (!request_region(I8042_DATA_REG, 16, "i8042")) if (!request_region(I8042_DATA_REG, 16, "i8042"))
return -1; return -EBUSY;
#endif #endif
i8042_reset = 1; i8042_reset = 1;
#if defined(CONFIG_PPC64) #if defined(CONFIG_PPC64)
if (check_legacy_ioport(I8042_DATA_REG)) if (check_legacy_ioport(I8042_DATA_REG))
return -1; return -EBUSY;
if (!request_region(I8042_DATA_REG, 16, "i8042")) if (!request_region(I8042_DATA_REG, 16, "i8042"))
return -1; return -EBUSY;
#endif #endif
return 0; return 0;
} }
......
...@@ -58,7 +58,7 @@ static inline int i8042_platform_init(void) ...@@ -58,7 +58,7 @@ static inline int i8042_platform_init(void)
#if 0 #if 0
/* XXX sgi_kh is a virtual address */ /* XXX sgi_kh is a virtual address */
if (!request_mem_region(sgi_kh, sizeof(struct hpc_keyb), "i8042")) if (!request_mem_region(sgi_kh, sizeof(struct hpc_keyb), "i8042"))
return 1; return -EBUSY;
#endif #endif
i8042_reset = 1; i8042_reset = 1;
......
...@@ -53,7 +53,7 @@ static inline int i8042_platform_init(void) ...@@ -53,7 +53,7 @@ static inline int i8042_platform_init(void)
#if 0 #if 0
/* XXX JAZZ_KEYBOARD_ADDRESS is a virtual address */ /* XXX JAZZ_KEYBOARD_ADDRESS is a virtual address */
if (!request_mem_region(JAZZ_KEYBOARD_ADDRESS, 2, "i8042")) if (!request_mem_region(JAZZ_KEYBOARD_ADDRESS, 2, "i8042"))
return 1; return -EBUSY;
#endif #endif
return 0; return 0;
......
...@@ -48,10 +48,10 @@ static inline void i8042_write_command(int val) ...@@ -48,10 +48,10 @@ static inline void i8042_write_command(int val)
#define OBP_PS2MS_NAME1 "kdmouse" #define OBP_PS2MS_NAME1 "kdmouse"
#define OBP_PS2MS_NAME2 "mouse" #define OBP_PS2MS_NAME2 "mouse"
static int i8042_platform_init(void) static int __init i8042_platform_init(void)
{ {
#ifndef CONFIG_PCI #ifndef CONFIG_PCI
return -1; return -ENODEV;
#else #else
char prop[128]; char prop[128];
int len; int len;
...@@ -59,14 +59,14 @@ static int i8042_platform_init(void) ...@@ -59,14 +59,14 @@ static int i8042_platform_init(void)
len = prom_getproperty(prom_root_node, "name", prop, sizeof(prop)); len = prom_getproperty(prom_root_node, "name", prop, sizeof(prop));
if (len < 0) { if (len < 0) {
printk("i8042: Cannot get name property of root OBP node.\n"); printk("i8042: Cannot get name property of root OBP node.\n");
return -1; return -ENODEV;
} }
if (strncmp(prop, "SUNW,JavaStation-1", len) == 0) { if (strncmp(prop, "SUNW,JavaStation-1", len) == 0) {
/* Hardcoded values for MrCoffee. */ /* Hardcoded values for MrCoffee. */
i8042_kbd_irq = i8042_aux_irq = 13 | 0x20; i8042_kbd_irq = i8042_aux_irq = 13 | 0x20;
kbd_iobase = ioremap(0x71300060, 8); kbd_iobase = ioremap(0x71300060, 8);
if (!kbd_iobase) if (!kbd_iobase)
return -1; return -ENODEV;
} else { } else {
struct linux_ebus *ebus; struct linux_ebus *ebus;
struct linux_ebus_device *edev; struct linux_ebus_device *edev;
...@@ -78,7 +78,7 @@ static int i8042_platform_init(void) ...@@ -78,7 +78,7 @@ static int i8042_platform_init(void)
goto edev_found; goto edev_found;
} }
} }
return -1; return -ENODEV;
edev_found: edev_found:
for_each_edevchild(edev, child) { for_each_edevchild(edev, child) {
...@@ -96,7 +96,7 @@ static int i8042_platform_init(void) ...@@ -96,7 +96,7 @@ static int i8042_platform_init(void)
i8042_aux_irq == -1) { i8042_aux_irq == -1) {
printk("i8042: Error, 8042 device lacks both kbd and " printk("i8042: Error, 8042 device lacks both kbd and "
"mouse nodes.\n"); "mouse nodes.\n");
return -1; return -ENODEV;
} }
} }
......
...@@ -137,6 +137,13 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { ...@@ -137,6 +137,13 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T3010"), DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T3010"),
}, },
}, },
{
.ident = "Fujitsu-Siemens Lifebook E4010",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E4010"),
},
},
{ {
.ident = "Toshiba P10", .ident = "Toshiba P10",
.matches = { .matches = {
...@@ -256,9 +263,10 @@ static void i8042_pnp_exit(void) ...@@ -256,9 +263,10 @@ static void i8042_pnp_exit(void)
} }
} }
static int i8042_pnp_init(void) static int __init i8042_pnp_init(void)
{ {
int result_kbd, result_aux; int result_kbd = 0, result_aux = 0;
char kbd_irq_str[4] = { 0 }, aux_irq_str[4] = { 0 };
if (i8042_nopnp) { if (i8042_nopnp) {
printk(KERN_INFO "i8042: PNP detection disabled\n"); printk(KERN_INFO "i8042: PNP detection disabled\n");
...@@ -267,6 +275,7 @@ static int i8042_pnp_init(void) ...@@ -267,6 +275,7 @@ static int i8042_pnp_init(void)
if ((result_kbd = pnp_register_driver(&i8042_pnp_kbd_driver)) >= 0) if ((result_kbd = pnp_register_driver(&i8042_pnp_kbd_driver)) >= 0)
i8042_pnp_kbd_registered = 1; i8042_pnp_kbd_registered = 1;
if ((result_aux = pnp_register_driver(&i8042_pnp_aux_driver)) >= 0) if ((result_aux = pnp_register_driver(&i8042_pnp_aux_driver)) >= 0)
i8042_pnp_aux_registered = 1; i8042_pnp_aux_registered = 1;
...@@ -280,6 +289,27 @@ static int i8042_pnp_init(void) ...@@ -280,6 +289,27 @@ static int i8042_pnp_init(void)
#endif #endif
} }
if (result_kbd > 0)
snprintf(kbd_irq_str, sizeof(kbd_irq_str),
"%d", i8042_pnp_kbd_irq);
if (result_aux > 0)
snprintf(aux_irq_str, sizeof(aux_irq_str),
"%d", i8042_pnp_aux_irq);
printk(KERN_INFO "PNP: PS/2 Controller [%s%s%s] at %#x,%#x irq %s%s%s\n",
i8042_pnp_kbd_name, (result_kbd > 0 && result_aux > 0) ? "," : "",
i8042_pnp_aux_name,
i8042_pnp_data_reg, i8042_pnp_command_reg,
kbd_irq_str, (result_kbd > 0 && result_aux > 0) ? "," : "",
aux_irq_str);
#if defined(__ia64__)
if (result_kbd <= 0)
i8042_nokbd = 1;
if (result_aux <= 0)
i8042_noaux = 1;
#endif
if (((i8042_pnp_data_reg & ~0xf) == (i8042_data_reg & ~0xf) && if (((i8042_pnp_data_reg & ~0xf) == (i8042_data_reg & ~0xf) &&
i8042_pnp_data_reg != i8042_data_reg) || !i8042_pnp_data_reg) { i8042_pnp_data_reg != i8042_data_reg) || !i8042_pnp_data_reg) {
printk(KERN_WARNING "PNP: PS/2 controller has invalid data port %#x; using default %#x\n", printk(KERN_WARNING "PNP: PS/2 controller has invalid data port %#x; using default %#x\n",
...@@ -294,53 +324,47 @@ static int i8042_pnp_init(void) ...@@ -294,53 +324,47 @@ static int i8042_pnp_init(void)
i8042_pnp_command_reg = i8042_command_reg; i8042_pnp_command_reg = i8042_command_reg;
} }
if (!i8042_pnp_kbd_irq) { if (!i8042_nokbd && !i8042_pnp_kbd_irq) {
printk(KERN_WARNING "PNP: PS/2 controller doesn't have KBD irq; using default %#x\n", i8042_kbd_irq); printk(KERN_WARNING "PNP: PS/2 controller doesn't have KBD irq; using default %d\n", i8042_kbd_irq);
i8042_pnp_kbd_irq = i8042_kbd_irq; i8042_pnp_kbd_irq = i8042_kbd_irq;
} }
if (!i8042_pnp_aux_irq) { if (!i8042_noaux && !i8042_pnp_aux_irq) {
printk(KERN_WARNING "PNP: PS/2 controller doesn't have AUX irq; using default %#x\n", i8042_aux_irq); printk(KERN_WARNING "PNP: PS/2 controller doesn't have AUX irq; using default %d\n", i8042_aux_irq);
i8042_pnp_aux_irq = i8042_aux_irq; i8042_pnp_aux_irq = i8042_aux_irq;
} }
#if defined(__ia64__)
if (result_aux <= 0)
i8042_noaux = 1;
#endif
i8042_data_reg = i8042_pnp_data_reg; i8042_data_reg = i8042_pnp_data_reg;
i8042_command_reg = i8042_pnp_command_reg; i8042_command_reg = i8042_pnp_command_reg;
i8042_kbd_irq = i8042_pnp_kbd_irq; i8042_kbd_irq = i8042_pnp_kbd_irq;
i8042_aux_irq = i8042_pnp_aux_irq; i8042_aux_irq = i8042_pnp_aux_irq;
printk(KERN_INFO "PNP: PS/2 Controller [%s%s%s] at %#x,%#x irq %d%s%d\n",
i8042_pnp_kbd_name, (result_kbd > 0 && result_aux > 0) ? "," : "", i8042_pnp_aux_name,
i8042_data_reg, i8042_command_reg, i8042_kbd_irq,
(result_aux > 0) ? "," : "", i8042_aux_irq);
return 0; return 0;
} }
#else
static inline int i8042_pnp_init(void) { return 0; }
static inline void i8042_pnp_exit(void) { }
#endif #endif
static inline int i8042_platform_init(void) static int __init i8042_platform_init(void)
{ {
int retval;
/* /*
* On ix86 platforms touching the i8042 data register region can do really * On ix86 platforms touching the i8042 data register region can do really
* bad things. Because of this the region is always reserved on ix86 boxes. * bad things. Because of this the region is always reserved on ix86 boxes.
* *
* if (!request_region(I8042_DATA_REG, 16, "i8042")) * if (!request_region(I8042_DATA_REG, 16, "i8042"))
* return -1; * return -EBUSY;
*/ */
i8042_kbd_irq = I8042_MAP_IRQ(1); i8042_kbd_irq = I8042_MAP_IRQ(1);
i8042_aux_irq = I8042_MAP_IRQ(12); i8042_aux_irq = I8042_MAP_IRQ(12);
#ifdef CONFIG_PNP retval = i8042_pnp_init();
if (i8042_pnp_init()) if (retval)
return -1; return retval;
#endif
#if defined(__ia64__) #if defined(__ia64__)
i8042_reset = 1; i8042_reset = 1;
...@@ -354,14 +378,12 @@ static inline int i8042_platform_init(void) ...@@ -354,14 +378,12 @@ static inline int i8042_platform_init(void)
i8042_nomux = 1; i8042_nomux = 1;
#endif #endif
return 0; return retval;
} }
static inline void i8042_platform_exit(void) static inline void i8042_platform_exit(void)
{ {
#ifdef CONFIG_PNP
i8042_pnp_exit(); i8042_pnp_exit();
#endif
} }
#endif /* _I8042_X86IA64IO_H */ #endif /* _I8042_X86IA64IO_H */
...@@ -27,6 +27,10 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); ...@@ -27,6 +27,10 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("i8042 keyboard and mouse controller driver"); MODULE_DESCRIPTION("i8042 keyboard and mouse controller driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static unsigned int i8042_nokbd;
module_param_named(nokbd, i8042_nokbd, bool, 0);
MODULE_PARM_DESC(nokbd, "Do not probe or use KBD port.");
static unsigned int i8042_noaux; static unsigned int i8042_noaux;
module_param_named(noaux, i8042_noaux, bool, 0); module_param_named(noaux, i8042_noaux, bool, 0);
MODULE_PARM_DESC(noaux, "Do not probe or use AUX (mouse) port."); MODULE_PARM_DESC(noaux, "Do not probe or use AUX (mouse) port.");
...@@ -338,10 +342,10 @@ static int i8042_open(struct serio *serio) ...@@ -338,10 +342,10 @@ static int i8042_open(struct serio *serio)
return 0; return 0;
activate_fail: activate_fail:
free_irq(port->irq, i8042_request_irq_cookie); free_irq(port->irq, i8042_request_irq_cookie);
irq_fail: irq_fail:
serio_unregister_port_delayed(serio); serio_unregister_port_delayed(serio);
return -1; return -1;
...@@ -485,7 +489,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -485,7 +489,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs)
serio_interrupt(port->serio, data, dfl, regs); serio_interrupt(port->serio, data, dfl, regs);
ret = 1; ret = 1;
out: out:
return IRQ_RETVAL(ret); return IRQ_RETVAL(ret);
} }
...@@ -552,7 +556,7 @@ static int i8042_enable_mux_ports(void) ...@@ -552,7 +556,7 @@ static int i8042_enable_mux_ports(void)
* Enable all muxed ports. * Enable all muxed ports.
*/ */
for (i = 0; i < 4; i++) { for (i = 0; i < I8042_NUM_MUX_PORTS; i++) {
i8042_command(&param, I8042_CMD_MUX_PFX + i); i8042_command(&param, I8042_CMD_MUX_PFX + i);
i8042_command(&param, I8042_CMD_AUX_ENABLE); i8042_command(&param, I8042_CMD_AUX_ENABLE);
} }
...@@ -682,7 +686,7 @@ static int __init i8042_port_register(struct i8042_port *port) ...@@ -682,7 +686,7 @@ static int __init i8042_port_register(struct i8042_port *port)
kfree(port->serio); kfree(port->serio);
port->serio = NULL; port->serio = NULL;
i8042_ctr |= port->disable; i8042_ctr |= port->disable;
return -1; return -EIO;
} }
printk(KERN_INFO "serio: i8042 %s port at %#lx,%#lx irq %d\n", printk(KERN_INFO "serio: i8042 %s port at %#lx,%#lx irq %d\n",
...@@ -977,85 +981,88 @@ static struct device_driver i8042_driver = { ...@@ -977,85 +981,88 @@ static struct device_driver i8042_driver = {
.shutdown = i8042_shutdown, .shutdown = i8042_shutdown,
}; };
static void __init i8042_create_kbd_port(void) static int __init i8042_create_kbd_port(void)
{ {
struct serio *serio; struct serio *serio;
struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO]; struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO];
serio = kmalloc(sizeof(struct serio), GFP_KERNEL); serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
if (serio) { if (!serio)
memset(serio, 0, sizeof(struct serio)); return -ENOMEM;
serio->id.type = i8042_direct ? SERIO_8042 : SERIO_8042_XL;
serio->write = i8042_dumbkbd ? NULL : i8042_kbd_write; serio->id.type = i8042_direct ? SERIO_8042 : SERIO_8042_XL;
serio->open = i8042_open; serio->write = i8042_dumbkbd ? NULL : i8042_kbd_write;
serio->close = i8042_close; serio->open = i8042_open;
serio->start = i8042_start; serio->close = i8042_close;
serio->stop = i8042_stop; serio->start = i8042_start;
serio->port_data = port; serio->stop = i8042_stop;
serio->dev.parent = &i8042_platform_device->dev; serio->port_data = port;
strlcpy(serio->name, "i8042 Kbd Port", sizeof(serio->name)); serio->dev.parent = &i8042_platform_device->dev;
strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys)); strlcpy(serio->name, "i8042 Kbd Port", sizeof(serio->name));
strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys));
port->serio = serio;
i8042_port_register(port); port->serio = serio;
}
return i8042_port_register(port);
} }
static void __init i8042_create_aux_port(void) static int __init i8042_create_aux_port(void)
{ {
struct serio *serio; struct serio *serio;
struct i8042_port *port = &i8042_ports[I8042_AUX_PORT_NO]; struct i8042_port *port = &i8042_ports[I8042_AUX_PORT_NO];
serio = kmalloc(sizeof(struct serio), GFP_KERNEL); serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
if (serio) { if (!serio)
memset(serio, 0, sizeof(struct serio)); return -ENOMEM;
serio->id.type = SERIO_8042;
serio->write = i8042_aux_write; serio->id.type = SERIO_8042;
serio->open = i8042_open; serio->write = i8042_aux_write;
serio->close = i8042_close; serio->open = i8042_open;
serio->start = i8042_start; serio->close = i8042_close;
serio->stop = i8042_stop; serio->start = i8042_start;
serio->port_data = port; serio->stop = i8042_stop;
serio->dev.parent = &i8042_platform_device->dev; serio->port_data = port;
strlcpy(serio->name, "i8042 Aux Port", sizeof(serio->name)); serio->dev.parent = &i8042_platform_device->dev;
strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys)); strlcpy(serio->name, "i8042 Aux Port", sizeof(serio->name));
strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys));
port->serio = serio;
i8042_port_register(port); port->serio = serio;
}
return i8042_port_register(port);
} }
static void __init i8042_create_mux_port(int index) static int __init i8042_create_mux_port(int index)
{ {
struct serio *serio; struct serio *serio;
struct i8042_port *port = &i8042_ports[I8042_MUX_PORT_NO + index]; struct i8042_port *port = &i8042_ports[I8042_MUX_PORT_NO + index];
serio = kmalloc(sizeof(struct serio), GFP_KERNEL); serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
if (serio) { if (!serio)
memset(serio, 0, sizeof(struct serio)); return -ENOMEM;
serio->id.type = SERIO_8042;
serio->write = i8042_aux_write; serio->id.type = SERIO_8042;
serio->open = i8042_open; serio->write = i8042_aux_write;
serio->close = i8042_close; serio->open = i8042_open;
serio->start = i8042_start; serio->close = i8042_close;
serio->stop = i8042_stop; serio->start = i8042_start;
serio->port_data = port; serio->stop = i8042_stop;
serio->dev.parent = &i8042_platform_device->dev; serio->port_data = port;
snprintf(serio->name, sizeof(serio->name), "i8042 Aux-%d Port", index); serio->dev.parent = &i8042_platform_device->dev;
snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, index + 1); snprintf(serio->name, sizeof(serio->name), "i8042 Aux-%d Port", index);
snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, index + 1);
*port = i8042_ports[I8042_AUX_PORT_NO];
port->exists = 0; *port = i8042_ports[I8042_AUX_PORT_NO];
snprintf(port->name, sizeof(port->name), "AUX%d", index); port->exists = 0;
port->mux = index; snprintf(port->name, sizeof(port->name), "AUX%d", index);
port->serio = serio; port->mux = index;
i8042_port_register(port); port->serio = serio;
}
return i8042_port_register(port);
} }
static int __init i8042_init(void) static int __init i8042_init(void)
{ {
int i; int i, have_ports = 0;
int err; int err;
dbg_init(); dbg_init();
...@@ -1063,43 +1070,73 @@ static int __init i8042_init(void) ...@@ -1063,43 +1070,73 @@ static int __init i8042_init(void)
init_timer(&i8042_timer); init_timer(&i8042_timer);
i8042_timer.function = i8042_timer_func; i8042_timer.function = i8042_timer_func;
if (i8042_platform_init()) err = i8042_platform_init();
return -EBUSY; if (err)
return err;
i8042_ports[I8042_AUX_PORT_NO].irq = I8042_AUX_IRQ; i8042_ports[I8042_AUX_PORT_NO].irq = I8042_AUX_IRQ;
i8042_ports[I8042_KBD_PORT_NO].irq = I8042_KBD_IRQ; i8042_ports[I8042_KBD_PORT_NO].irq = I8042_KBD_IRQ;
if (i8042_controller_init()) { if (i8042_controller_init()) {
i8042_platform_exit(); err = -ENODEV;
return -ENODEV; goto err_platform_exit;
} }
err = driver_register(&i8042_driver); err = driver_register(&i8042_driver);
if (err) { if (err)
i8042_platform_exit(); goto err_controller_cleanup;
return err;
}
i8042_platform_device = platform_device_register_simple("i8042", -1, NULL, 0); i8042_platform_device = platform_device_register_simple("i8042", -1, NULL, 0);
if (IS_ERR(i8042_platform_device)) { if (IS_ERR(i8042_platform_device)) {
driver_unregister(&i8042_driver); err = PTR_ERR(i8042_platform_device);
i8042_platform_exit(); goto err_unregister_driver;
return PTR_ERR(i8042_platform_device);
} }
if (!i8042_noaux && !i8042_check_aux()) { if (!i8042_noaux && !i8042_check_aux()) {
if (!i8042_nomux && !i8042_check_mux()) if (!i8042_nomux && !i8042_check_mux()) {
for (i = 0; i < I8042_NUM_MUX_PORTS; i++) for (i = 0; i < I8042_NUM_MUX_PORTS; i++) {
i8042_create_mux_port(i); err = i8042_create_mux_port(i);
else if (err)
i8042_create_aux_port(); goto err_unregister_ports;
}
} else {
err = i8042_create_aux_port();
if (err)
goto err_unregister_ports;
}
have_ports = 1;
} }
i8042_create_kbd_port(); if (!i8042_nokbd) {
err = i8042_create_kbd_port();
if (err)
goto err_unregister_ports;
have_ports = 1;
}
if (!have_ports) {
err = -ENODEV;
goto err_unregister_device;
}
mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
return 0; return 0;
err_unregister_ports:
for (i = 0; i < I8042_NUM_PORTS; i++)
if (i8042_ports[i].serio)
serio_unregister_port(i8042_ports[i].serio);
err_unregister_device:
platform_device_unregister(i8042_platform_device);
err_unregister_driver:
driver_unregister(&i8042_driver);
err_controller_cleanup:
i8042_controller_cleanup();
err_platform_exit:
i8042_platform_exit();
return err;
} }
static void __exit i8042_exit(void) static void __exit i8042_exit(void)
......
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
* USB HID support for Linux * USB HID support for Linux
* *
* Copyright (c) 1999 Andreas Gal * Copyright (c) 1999 Andreas Gal
* Copyright (c) 2000-2001 Vojtech Pavlik <vojtech@suse.cz> * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
*/ */
/* /*
...@@ -38,7 +39,7 @@ ...@@ -38,7 +39,7 @@
* Version Information * Version Information
*/ */
#define DRIVER_VERSION "v2.01" #define DRIVER_VERSION "v2.6"
#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik" #define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik"
#define DRIVER_DESC "USB HID core driver" #define DRIVER_DESC "USB HID core driver"
#define DRIVER_LICENSE "GPL" #define DRIVER_LICENSE "GPL"
...@@ -1058,8 +1059,8 @@ static int hid_submit_ctrl(struct hid_device *hid) ...@@ -1058,8 +1059,8 @@ static int hid_submit_ctrl(struct hid_device *hid)
if (maxpacket > 0) { if (maxpacket > 0) {
padlen = (len + maxpacket - 1) / maxpacket; padlen = (len + maxpacket - 1) / maxpacket;
padlen *= maxpacket; padlen *= maxpacket;
if (padlen > HID_BUFFER_SIZE) if (padlen > hid->bufsize)
padlen = HID_BUFFER_SIZE; padlen = hid->bufsize;
} else } else
padlen = 0; padlen = 0;
hid->urbctrl->transfer_buffer_length = padlen; hid->urbctrl->transfer_buffer_length = padlen;
...@@ -1096,6 +1097,7 @@ static void hid_irq_out(struct urb *urb, struct pt_regs *regs) ...@@ -1096,6 +1097,7 @@ static void hid_irq_out(struct urb *urb, struct pt_regs *regs)
switch (urb->status) { switch (urb->status) {
case 0: /* success */ case 0: /* success */
break;
case -ESHUTDOWN: /* unplug */ case -ESHUTDOWN: /* unplug */
case -EILSEQ: /* unplug timeout on uhci */ case -EILSEQ: /* unplug timeout on uhci */
unplug = 1; unplug = 1;
...@@ -1143,6 +1145,7 @@ static void hid_ctrl(struct urb *urb, struct pt_regs *regs) ...@@ -1143,6 +1145,7 @@ static void hid_ctrl(struct urb *urb, struct pt_regs *regs)
case 0: /* success */ case 0: /* success */
if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN) if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN)
hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, 0, regs); hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, 0, regs);
break;
case -ESHUTDOWN: /* unplug */ case -ESHUTDOWN: /* unplug */
case -EILSEQ: /* unplug timectrl on uhci */ case -EILSEQ: /* unplug timectrl on uhci */
unplug = 1; unplug = 1;
...@@ -1284,13 +1287,8 @@ void hid_init_reports(struct hid_device *hid) ...@@ -1284,13 +1287,8 @@ void hid_init_reports(struct hid_device *hid)
struct hid_report *report; struct hid_report *report;
int err, ret; int err, ret;
list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list) { list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list)
int size = ((report->size - 1) >> 3) + 1 + hid->report_enum[HID_INPUT_REPORT].numbered;
if (size > HID_BUFFER_SIZE) size = HID_BUFFER_SIZE;
if (size > hid->urbin->transfer_buffer_length)
hid->urbin->transfer_buffer_length = size;
hid_submit_report(hid, report, USB_DIR_IN); hid_submit_report(hid, report, USB_DIR_IN);
}
list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list) list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
hid_submit_report(hid, report, USB_DIR_IN); hid_submit_report(hid, report, USB_DIR_IN);
...@@ -1372,12 +1370,14 @@ void hid_init_reports(struct hid_device *hid) ...@@ -1372,12 +1370,14 @@ void hid_init_reports(struct hid_device *hid)
#define USB_VENDOR_ID_A4TECH 0x09da #define USB_VENDOR_ID_A4TECH 0x09da
#define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006 #define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006
#define USB_VENDOR_ID_AASHIMA 0x06D6 #define USB_VENDOR_ID_AASHIMA 0x06d6
#define USB_DEVICE_ID_AASHIMA_GAMEPAD 0x0025 #define USB_DEVICE_ID_AASHIMA_GAMEPAD 0x0025
#define USB_DEVICE_ID_AASHIMA_PREDATOR 0x0026
#define USB_VENDOR_ID_CYPRESS 0x04b4 #define USB_VENDOR_ID_CYPRESS 0x04b4
#define USB_DEVICE_ID_CYPRESS_MOUSE 0x0001 #define USB_DEVICE_ID_CYPRESS_MOUSE 0x0001
#define USB_DEVICE_ID_CYPRESS_HIDCOM 0x5500 #define USB_DEVICE_ID_CYPRESS_HIDCOM 0x5500
#define USB_DEVICE_ID_CYPRESS_ULTRAMOUSE 0x7417
#define USB_VENDOR_ID_BERKSHIRE 0x0c98 #define USB_VENDOR_ID_BERKSHIRE 0x0c98
#define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140 #define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140
...@@ -1432,7 +1432,7 @@ void hid_init_reports(struct hid_device *hid) ...@@ -1432,7 +1432,7 @@ void hid_init_reports(struct hid_device *hid)
#define USB_DEVICE_ID_VERNIER_CYCLOPS 0x0004 #define USB_DEVICE_ID_VERNIER_CYCLOPS 0x0004
#define USB_VENDOR_ID_LD 0x0f11 #define USB_VENDOR_ID_LD 0x0f11
#define USB_DEVICE_ID_CASSY 0x1000 #define USB_DEVICE_ID_CASSY 0x1000
#define USB_DEVICE_ID_POCKETCASSY 0x1010 #define USB_DEVICE_ID_POCKETCASSY 0x1010
#define USB_DEVICE_ID_MOBILECASSY 0x1020 #define USB_DEVICE_ID_MOBILECASSY 0x1020
#define USB_DEVICE_ID_JWM 0x1080 #define USB_DEVICE_ID_JWM 0x1080
...@@ -1445,7 +1445,8 @@ void hid_init_reports(struct hid_device *hid) ...@@ -1445,7 +1445,8 @@ void hid_init_reports(struct hid_device *hid)
#define USB_DEVICE_ID_POWERCONTROL 0x2030 #define USB_DEVICE_ID_POWERCONTROL 0x2030
#define USB_VENDOR_ID_APPLE 0x05ac #define USB_VENDOR_ID_APPLE 0x05ac
#define USB_DEVICE_ID_APPLE_BLUETOOTH 0x1000 #define USB_DEVICE_ID_APPLE_POWERMOUSE 0x0304
#define USB_DEVICE_ID_APPLE_BLUETOOTH 0x1000
/* /*
* Alphabetically sorted blacklist by quirk type. * Alphabetically sorted blacklist by quirk type.
...@@ -1471,6 +1472,7 @@ static struct hid_blacklist { ...@@ -1471,6 +1472,7 @@ static struct hid_blacklist {
{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW48, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW48, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW28, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW28, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE },
...@@ -1551,10 +1553,12 @@ static struct hid_blacklist { ...@@ -1551,10 +1553,12 @@ static struct hid_blacklist {
{ USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_USBHUB_KB, HID_QUIRK_NOGET}, { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_USBHUB_KB, HID_QUIRK_NOGET},
{ USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET }, { USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_POWERMOUSE, HID_QUIRK_2WHEEL_POWERMOUSE },
{ USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 }, { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 },
{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_5 }, { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_5 },
{ USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_GAMEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_GAMEPAD, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
...@@ -1567,15 +1571,32 @@ static struct hid_blacklist { ...@@ -1567,15 +1571,32 @@ static struct hid_blacklist {
{ 0, 0 } { 0, 0 }
}; };
/*
* Traverse the supplied list of reports and find the longest
*/
static void hid_find_max_report(struct hid_device *hid, unsigned int type, int *max)
{
struct hid_report *report;
int size;
list_for_each_entry(report, &hid->report_enum[type].report_list, list) {
size = ((report->size - 1) >> 3) + 1;
if (type == HID_INPUT_REPORT && hid->report_enum[type].numbered)
size++;
if (*max < size)
*max = size;
}
}
static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid) static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid)
{ {
if (!(hid->inbuf = usb_buffer_alloc(dev, HID_BUFFER_SIZE, SLAB_ATOMIC, &hid->inbuf_dma))) if (!(hid->inbuf = usb_buffer_alloc(dev, hid->bufsize, SLAB_ATOMIC, &hid->inbuf_dma)))
return -1; return -1;
if (!(hid->outbuf = usb_buffer_alloc(dev, HID_BUFFER_SIZE, SLAB_ATOMIC, &hid->outbuf_dma))) if (!(hid->outbuf = usb_buffer_alloc(dev, hid->bufsize, SLAB_ATOMIC, &hid->outbuf_dma)))
return -1; return -1;
if (!(hid->cr = usb_buffer_alloc(dev, sizeof(*(hid->cr)), SLAB_ATOMIC, &hid->cr_dma))) if (!(hid->cr = usb_buffer_alloc(dev, sizeof(*(hid->cr)), SLAB_ATOMIC, &hid->cr_dma)))
return -1; return -1;
if (!(hid->ctrlbuf = usb_buffer_alloc(dev, HID_BUFFER_SIZE, SLAB_ATOMIC, &hid->ctrlbuf_dma))) if (!(hid->ctrlbuf = usb_buffer_alloc(dev, hid->bufsize, SLAB_ATOMIC, &hid->ctrlbuf_dma)))
return -1; return -1;
return 0; return 0;
...@@ -1584,13 +1605,13 @@ static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid) ...@@ -1584,13 +1605,13 @@ static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid)
static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid) static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
{ {
if (hid->inbuf) if (hid->inbuf)
usb_buffer_free(dev, HID_BUFFER_SIZE, hid->inbuf, hid->inbuf_dma); usb_buffer_free(dev, hid->bufsize, hid->inbuf, hid->inbuf_dma);
if (hid->outbuf) if (hid->outbuf)
usb_buffer_free(dev, HID_BUFFER_SIZE, hid->outbuf, hid->outbuf_dma); usb_buffer_free(dev, hid->bufsize, hid->outbuf, hid->outbuf_dma);
if (hid->cr) if (hid->cr)
usb_buffer_free(dev, sizeof(*(hid->cr)), hid->cr, hid->cr_dma); usb_buffer_free(dev, sizeof(*(hid->cr)), hid->cr, hid->cr_dma);
if (hid->ctrlbuf) if (hid->ctrlbuf)
usb_buffer_free(dev, HID_BUFFER_SIZE, hid->ctrlbuf, hid->ctrlbuf_dma); usb_buffer_free(dev, hid->bufsize, hid->ctrlbuf, hid->ctrlbuf_dma);
} }
static struct hid_device *usb_hid_configure(struct usb_interface *intf) static struct hid_device *usb_hid_configure(struct usb_interface *intf)
...@@ -1601,7 +1622,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) ...@@ -1601,7 +1622,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
struct hid_device *hid; struct hid_device *hid;
unsigned quirks = 0, rsize = 0; unsigned quirks = 0, rsize = 0;
char *buf, *rdesc; char *buf, *rdesc;
int n; int n, insize = 0;
for (n = 0; hid_blacklist[n].idVendor; n++) for (n = 0; hid_blacklist[n].idVendor; n++)
if ((hid_blacklist[n].idVendor == le16_to_cpu(dev->descriptor.idVendor)) && if ((hid_blacklist[n].idVendor == le16_to_cpu(dev->descriptor.idVendor)) &&
...@@ -1655,6 +1676,19 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) ...@@ -1655,6 +1676,19 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
kfree(rdesc); kfree(rdesc);
hid->quirks = quirks; hid->quirks = quirks;
hid->bufsize = HID_MIN_BUFFER_SIZE;
hid_find_max_report(hid, HID_INPUT_REPORT, &hid->bufsize);
hid_find_max_report(hid, HID_OUTPUT_REPORT, &hid->bufsize);
hid_find_max_report(hid, HID_FEATURE_REPORT, &hid->bufsize);
if (hid->bufsize > HID_MAX_BUFFER_SIZE)
hid->bufsize = HID_MAX_BUFFER_SIZE;
hid_find_max_report(hid, HID_INPUT_REPORT, &insize);
if (insize > HID_MAX_BUFFER_SIZE)
insize = HID_MAX_BUFFER_SIZE;
if (hid_alloc_buffers(dev, hid)) { if (hid_alloc_buffers(dev, hid)) {
hid_free_buffers(dev, hid); hid_free_buffers(dev, hid);
goto fail; goto fail;
...@@ -1685,7 +1719,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) ...@@ -1685,7 +1719,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
if (!(hid->urbin = usb_alloc_urb(0, GFP_KERNEL))) if (!(hid->urbin = usb_alloc_urb(0, GFP_KERNEL)))
goto fail; goto fail;
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, 0, usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, insize,
hid_irq_in, hid, interval); hid_irq_in, hid, interval);
hid->urbin->transfer_dma = hid->inbuf_dma; hid->urbin->transfer_dma = hid->inbuf_dma;
hid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; hid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
......
...@@ -85,6 +85,23 @@ static const struct hid_usage_entry hid_usage_table[] = { ...@@ -85,6 +85,23 @@ static const struct hid_usage_entry hid_usage_table[] = {
{0, 0x91, "D-PadDown"}, {0, 0x91, "D-PadDown"},
{0, 0x92, "D-PadRight"}, {0, 0x92, "D-PadRight"},
{0, 0x93, "D-PadLeft"}, {0, 0x93, "D-PadLeft"},
{ 2, 0, "Simulation" },
{0, 0xb0, "Aileron"},
{0, 0xb1, "AileronTrim"},
{0, 0xb2, "Anti-Torque"},
{0, 0xb3, "Autopilot"},
{0, 0xb4, "Chaff"},
{0, 0xb5, "Collective"},
{0, 0xb6, "DiveBrake"},
{0, 0xb7, "ElectronicCountermeasures"},
{0, 0xb8, "Elevator"},
{0, 0xb9, "ElevatorTrim"},
{0, 0xba, "Rudder"},
{0, 0xbb, "Throttle"},
{0, 0xbc, "FlightCommunications"},
{0, 0xbd, "FlareRelease"},
{0, 0xbe, "LandingGear"},
{0, 0xbf, "ToeBrake"},
{ 7, 0, "Keyboard" }, { 7, 0, "Keyboard" },
{ 8, 0, "LED" }, { 8, 0, "LED" },
{0, 0x01, "NumLock"}, {0, 0x01, "NumLock"},
...@@ -92,6 +109,7 @@ static const struct hid_usage_entry hid_usage_table[] = { ...@@ -92,6 +109,7 @@ static const struct hid_usage_entry hid_usage_table[] = {
{0, 0x03, "ScrollLock"}, {0, 0x03, "ScrollLock"},
{0, 0x04, "Compose"}, {0, 0x04, "Compose"},
{0, 0x05, "Kana"}, {0, 0x05, "Kana"},
{0, 0x4b, "GenericIndicator"},
{ 9, 0, "Button" }, { 9, 0, "Button" },
{ 10, 0, "Ordinal" }, { 10, 0, "Ordinal" },
{ 12, 0, "Consumer" }, { 12, 0, "Consumer" },
...@@ -574,7 +592,8 @@ static char *keys[KEY_MAX + 1] = { ...@@ -574,7 +592,8 @@ static char *keys[KEY_MAX + 1] = {
[KEY_EXIT] = "Exit", [KEY_MOVE] = "Move", [KEY_EXIT] = "Exit", [KEY_MOVE] = "Move",
[KEY_EDIT] = "Edit", [KEY_SCROLLUP] = "ScrollUp", [KEY_EDIT] = "Edit", [KEY_SCROLLUP] = "ScrollUp",
[KEY_SCROLLDOWN] = "ScrollDown", [KEY_KPLEFTPAREN] = "KPLeftParenthesis", [KEY_SCROLLDOWN] = "ScrollDown", [KEY_KPLEFTPAREN] = "KPLeftParenthesis",
[KEY_KPRIGHTPAREN] = "KPRightParenthesis", [KEY_F13] = "F13", [KEY_KPRIGHTPAREN] = "KPRightParenthesis", [KEY_NEW] = "New",
[KEY_REDO] = "Redo", [KEY_F13] = "F13",
[KEY_F14] = "F14", [KEY_F15] = "F15", [KEY_F14] = "F14", [KEY_F15] = "F15",
[KEY_F16] = "F16", [KEY_F17] = "F17", [KEY_F16] = "F16", [KEY_F17] = "F17",
[KEY_F18] = "F18", [KEY_F19] = "F19", [KEY_F18] = "F18", [KEY_F19] = "F19",
...@@ -584,15 +603,15 @@ static char *keys[KEY_MAX + 1] = { ...@@ -584,15 +603,15 @@ static char *keys[KEY_MAX + 1] = {
[KEY_PAUSECD] = "PauseCD", [KEY_PROG3] = "Prog3", [KEY_PAUSECD] = "PauseCD", [KEY_PROG3] = "Prog3",
[KEY_PROG4] = "Prog4", [KEY_SUSPEND] = "Suspend", [KEY_PROG4] = "Prog4", [KEY_SUSPEND] = "Suspend",
[KEY_CLOSE] = "Close", [KEY_PLAY] = "Play", [KEY_CLOSE] = "Close", [KEY_PLAY] = "Play",
[KEY_FASTFORWARD] = "Fast Forward", [KEY_BASSBOOST] = "Bass Boost", [KEY_FASTFORWARD] = "FastForward", [KEY_BASSBOOST] = "BassBoost",
[KEY_PRINT] = "Print", [KEY_HP] = "HP", [KEY_PRINT] = "Print", [KEY_HP] = "HP",
[KEY_CAMERA] = "Camera", [KEY_SOUND] = "Sound", [KEY_CAMERA] = "Camera", [KEY_SOUND] = "Sound",
[KEY_QUESTION] = "Question", [KEY_EMAIL] = "Email", [KEY_QUESTION] = "Question", [KEY_EMAIL] = "Email",
[KEY_CHAT] = "Chat", [KEY_SEARCH] = "Search", [KEY_CHAT] = "Chat", [KEY_SEARCH] = "Search",
[KEY_CONNECT] = "Connect", [KEY_FINANCE] = "Finance", [KEY_CONNECT] = "Connect", [KEY_FINANCE] = "Finance",
[KEY_SPORT] = "Sport", [KEY_SHOP] = "Shop", [KEY_SPORT] = "Sport", [KEY_SHOP] = "Shop",
[KEY_ALTERASE] = "Alternate Erase", [KEY_CANCEL] = "Cancel", [KEY_ALTERASE] = "AlternateErase", [KEY_CANCEL] = "Cancel",
[KEY_BRIGHTNESSDOWN] = "Brightness down", [KEY_BRIGHTNESSUP] = "Brightness up", [KEY_BRIGHTNESSDOWN] = "BrightnessDown", [KEY_BRIGHTNESSUP] = "BrightnessUp",
[KEY_MEDIA] = "Media", [KEY_UNKNOWN] = "Unknown", [KEY_MEDIA] = "Media", [KEY_UNKNOWN] = "Unknown",
[BTN_0] = "Btn0", [BTN_1] = "Btn1", [BTN_0] = "Btn0", [BTN_1] = "Btn1",
[BTN_2] = "Btn2", [BTN_3] = "Btn3", [BTN_2] = "Btn2", [BTN_3] = "Btn3",
...@@ -622,8 +641,8 @@ static char *keys[KEY_MAX + 1] = { ...@@ -622,8 +641,8 @@ static char *keys[KEY_MAX + 1] = {
[BTN_TOOL_AIRBRUSH] = "ToolAirbrush", [BTN_TOOL_FINGER] = "ToolFinger", [BTN_TOOL_AIRBRUSH] = "ToolAirbrush", [BTN_TOOL_FINGER] = "ToolFinger",
[BTN_TOOL_MOUSE] = "ToolMouse", [BTN_TOOL_LENS] = "ToolLens", [BTN_TOOL_MOUSE] = "ToolMouse", [BTN_TOOL_LENS] = "ToolLens",
[BTN_TOUCH] = "Touch", [BTN_STYLUS] = "Stylus", [BTN_TOUCH] = "Touch", [BTN_STYLUS] = "Stylus",
[BTN_STYLUS2] = "Stylus2", [BTN_TOOL_DOUBLETAP] = "Tool Doubletap", [BTN_STYLUS2] = "Stylus2", [BTN_TOOL_DOUBLETAP] = "ToolDoubleTap",
[BTN_TOOL_TRIPLETAP] = "Tool Tripletap", [BTN_GEAR_DOWN] = "WheelBtn", [BTN_TOOL_TRIPLETAP] = "ToolTripleTap", [BTN_GEAR_DOWN] = "WheelBtn",
[BTN_GEAR_UP] = "Gear up", [KEY_OK] = "Ok", [BTN_GEAR_UP] = "Gear up", [KEY_OK] = "Ok",
[KEY_SELECT] = "Select", [KEY_GOTO] = "Goto", [KEY_SELECT] = "Select", [KEY_GOTO] = "Goto",
[KEY_CLEAR] = "Clear", [KEY_POWER2] = "Power2", [KEY_CLEAR] = "Clear", [KEY_POWER2] = "Power2",
...@@ -659,6 +678,9 @@ static char *keys[KEY_MAX + 1] = { ...@@ -659,6 +678,9 @@ static char *keys[KEY_MAX + 1] = {
[KEY_TWEN] = "TWEN", [KEY_DEL_EOL] = "DeleteEOL", [KEY_TWEN] = "TWEN", [KEY_DEL_EOL] = "DeleteEOL",
[KEY_DEL_EOS] = "DeleteEOS", [KEY_INS_LINE] = "InsertLine", [KEY_DEL_EOS] = "DeleteEOS", [KEY_INS_LINE] = "InsertLine",
[KEY_DEL_LINE] = "DeleteLine", [KEY_DEL_LINE] = "DeleteLine",
[KEY_SEND] = "Send", [KEY_REPLY] = "Reply",
[KEY_FORWARDMAIL] = "ForwardMail", [KEY_SAVE] = "Save",
[KEY_DOCUMENTS] = "Documents",
}; };
static char *relatives[REL_MAX + 1] = { static char *relatives[REL_MAX + 1] = {
......
...@@ -78,8 +78,8 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -78,8 +78,8 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
{ {
struct input_dev *input = &hidinput->input; struct input_dev *input = &hidinput->input;
struct hid_device *device = hidinput->input.private; struct hid_device *device = hidinput->input.private;
int max, code; int max = 0, code;
unsigned long *bit; unsigned long *bit = NULL;
field->hidinput = hidinput; field->hidinput = hidinput;
...@@ -131,6 +131,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -131,6 +131,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
map_key(code); map_key(code);
break; break;
case HID_UP_SIMULATION:
switch (usage->hid & 0xffff) {
case 0xba: map_abs(ABS_RUDDER); break;
case 0xbb: map_abs(ABS_THROTTLE); break;
}
break;
case HID_UP_GENDESK: case HID_UP_GENDESK:
if ((usage->hid & 0xf0) == 0x80) { /* SystemControl */ if ((usage->hid & 0xf0) == 0x80) { /* SystemControl */
...@@ -238,8 +247,12 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -238,8 +247,12 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x000: goto ignore; case 0x000: goto ignore;
case 0x034: map_key_clear(KEY_SLEEP); break; case 0x034: map_key_clear(KEY_SLEEP); break;
case 0x036: map_key_clear(BTN_MISC); break; case 0x036: map_key_clear(BTN_MISC); break;
case 0x045: map_key_clear(KEY_RADIO); break;
case 0x08a: map_key_clear(KEY_WWW); break; case 0x08a: map_key_clear(KEY_WWW); break;
case 0x08d: map_key_clear(KEY_PROGRAM); break;
case 0x095: map_key_clear(KEY_HELP); break; case 0x095: map_key_clear(KEY_HELP); break;
case 0x09c: map_key_clear(KEY_CHANNELUP); break;
case 0x09d: map_key_clear(KEY_CHANNELDOWN); break;
case 0x0b0: map_key_clear(KEY_PLAY); break; case 0x0b0: map_key_clear(KEY_PLAY); break;
case 0x0b1: map_key_clear(KEY_PAUSE); break; case 0x0b1: map_key_clear(KEY_PAUSE); break;
case 0x0b2: map_key_clear(KEY_RECORD); break; case 0x0b2: map_key_clear(KEY_RECORD); break;
...@@ -259,6 +272,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -259,6 +272,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x18a: map_key_clear(KEY_MAIL); break; case 0x18a: map_key_clear(KEY_MAIL); break;
case 0x192: map_key_clear(KEY_CALC); break; case 0x192: map_key_clear(KEY_CALC); break;
case 0x194: map_key_clear(KEY_FILE); break; case 0x194: map_key_clear(KEY_FILE); break;
case 0x1a7: map_key_clear(KEY_DOCUMENTS); break;
case 0x201: map_key_clear(KEY_NEW); break;
case 0x207: map_key_clear(KEY_SAVE); break;
case 0x208: map_key_clear(KEY_PRINT); break;
case 0x209: map_key_clear(KEY_PROPS); break;
case 0x21a: map_key_clear(KEY_UNDO); break; case 0x21a: map_key_clear(KEY_UNDO); break;
case 0x21b: map_key_clear(KEY_COPY); break; case 0x21b: map_key_clear(KEY_COPY); break;
case 0x21c: map_key_clear(KEY_CUT); break; case 0x21c: map_key_clear(KEY_CUT); break;
...@@ -271,7 +289,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -271,7 +289,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x227: map_key_clear(KEY_REFRESH); break; case 0x227: map_key_clear(KEY_REFRESH); break;
case 0x22a: map_key_clear(KEY_BOOKMARKS); break; case 0x22a: map_key_clear(KEY_BOOKMARKS); break;
case 0x238: map_rel(REL_HWHEEL); break; case 0x238: map_rel(REL_HWHEEL); break;
default: goto unknown; case 0x279: map_key_clear(KEY_REDO); break;
case 0x289: map_key_clear(KEY_REPLY); break;
case 0x28b: map_key_clear(KEY_FORWARDMAIL); break;
case 0x28c: map_key_clear(KEY_SEND); break;
default: goto ignore;
} }
break; break;
...@@ -296,9 +318,42 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -296,9 +318,42 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
break; break;
case HID_UP_MSVENDOR: case HID_UP_MSVENDOR:
goto ignore; goto ignore;
case HID_UP_CUSTOM: /* Reported on Logitech and Powerbook USB keyboards */
set_bit(EV_REP, input->evbit);
switch(usage->hid & HID_USAGE) {
case 0x003: map_key_clear(KEY_FN); break;
default: goto ignore;
}
break;
case HID_UP_LOGIVENDOR: /* Reported on Logitech Ultra X Media Remote */
set_bit(EV_REP, input->evbit);
switch(usage->hid & HID_USAGE) {
case 0x004: map_key_clear(KEY_AGAIN); break;
case 0x00d: map_key_clear(KEY_HOME); break;
case 0x024: map_key_clear(KEY_SHUFFLE); break;
case 0x025: map_key_clear(KEY_TV); break;
case 0x026: map_key_clear(KEY_MENU); break;
case 0x031: map_key_clear(KEY_AUDIO); break;
case 0x032: map_key_clear(KEY_SUBTITLE); break;
case 0x033: map_key_clear(KEY_LAST); break;
case 0x047: map_key_clear(KEY_MP3); break;
case 0x048: map_key_clear(KEY_DVD); break;
case 0x049: map_key_clear(KEY_MEDIA); break;
case 0x04a: map_key_clear(KEY_VIDEO); break;
case 0x04b: map_key_clear(KEY_ANGLE); break;
case 0x04c: map_key_clear(KEY_LANGUAGE); break;
case 0x04d: map_key_clear(KEY_SUBTITLE); break;
case 0x051: map_key_clear(KEY_RED); break;
case 0x052: map_key_clear(KEY_CLOSE); break;
default: goto ignore;
}
break;
case HID_UP_PID: case HID_UP_PID:
set_bit(EV_FF, input->evbit); set_bit(EV_FF, input->evbit);
...@@ -349,6 +404,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -349,6 +404,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
if (usage->code > max) if (usage->code > max)
goto ignore; goto ignore;
if (((device->quirks & (HID_QUIRK_2WHEEL_POWERMOUSE)) && (usage->hid == 0x00010032)))
map_rel(REL_HWHEEL);
if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5)) && if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5)) &&
(usage->type == EV_REL) && (usage->code == REL_WHEEL)) (usage->type == EV_REL) && (usage->code == REL_WHEEL))
set_bit(REL_HWHEEL, bit); set_bit(REL_HWHEEL, bit);
......
...@@ -173,6 +173,7 @@ struct hid_item { ...@@ -173,6 +173,7 @@ struct hid_item {
#define HID_UP_UNDEFINED 0x00000000 #define HID_UP_UNDEFINED 0x00000000
#define HID_UP_GENDESK 0x00010000 #define HID_UP_GENDESK 0x00010000
#define HID_UP_SIMULATION 0x00020000
#define HID_UP_KEYBOARD 0x00070000 #define HID_UP_KEYBOARD 0x00070000
#define HID_UP_LED 0x00080000 #define HID_UP_LED 0x00080000
#define HID_UP_BUTTON 0x00090000 #define HID_UP_BUTTON 0x00090000
...@@ -182,6 +183,8 @@ struct hid_item { ...@@ -182,6 +183,8 @@ struct hid_item {
#define HID_UP_PID 0x000f0000 #define HID_UP_PID 0x000f0000
#define HID_UP_HPVENDOR 0xff7f0000 #define HID_UP_HPVENDOR 0xff7f0000
#define HID_UP_MSVENDOR 0xff000000 #define HID_UP_MSVENDOR 0xff000000
#define HID_UP_CUSTOM 0x00ff0000
#define HID_UP_LOGIVENDOR 0xffbc0000
#define HID_USAGE 0x0000ffff #define HID_USAGE 0x0000ffff
...@@ -242,6 +245,7 @@ struct hid_item { ...@@ -242,6 +245,7 @@ struct hid_item {
#define HID_QUIRK_2WHEEL_MOUSE_HACK_7 0x080 #define HID_QUIRK_2WHEEL_MOUSE_HACK_7 0x080
#define HID_QUIRK_2WHEEL_MOUSE_HACK_5 0x100 #define HID_QUIRK_2WHEEL_MOUSE_HACK_5 0x100
#define HID_QUIRK_2WHEEL_MOUSE_HACK_ON 0x200 #define HID_QUIRK_2WHEEL_MOUSE_HACK_ON 0x200
#define HID_QUIRK_2WHEEL_POWERMOUSE 0x400
/* /*
* This is the global environment of the parser. This information is * This is the global environment of the parser. This information is
...@@ -348,7 +352,8 @@ struct hid_report_enum { ...@@ -348,7 +352,8 @@ struct hid_report_enum {
#define HID_REPORT_TYPES 3 #define HID_REPORT_TYPES 3
#define HID_BUFFER_SIZE 64 /* use 64 for compatibility with all possible packetlen */ #define HID_MIN_BUFFER_SIZE 64 /* make sure there is at least a packet size of space */
#define HID_MAX_BUFFER_SIZE 4096 /* 4kb */
#define HID_CONTROL_FIFO_SIZE 256 /* to init devices with >100 reports */ #define HID_CONTROL_FIFO_SIZE 256 /* to init devices with >100 reports */
#define HID_OUTPUT_FIFO_SIZE 64 #define HID_OUTPUT_FIFO_SIZE 64
...@@ -386,6 +391,8 @@ struct hid_device { /* device report descriptor */ ...@@ -386,6 +391,8 @@ struct hid_device { /* device report descriptor */
unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */ unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
unsigned int bufsize; /* URB buffer size */
struct urb *urbin; /* Input URB */ struct urb *urbin; /* Input URB */
char *inbuf; /* Input buffer */ char *inbuf; /* Input buffer */
dma_addr_t inbuf_dma; /* Input buffer dma */ dma_addr_t inbuf_dma; /* Input buffer dma */
......
...@@ -507,6 +507,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd ...@@ -507,6 +507,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
return -EINVAL; return -EINVAL;
hid_submit_report(hid, report, USB_DIR_OUT); hid_submit_report(hid, report, USB_DIR_OUT);
hid_wait_io(hid);
return 0; return 0;
......
...@@ -289,6 +289,8 @@ struct input_absinfo { ...@@ -289,6 +289,8 @@ struct input_absinfo {
#define KEY_SCROLLDOWN 178 #define KEY_SCROLLDOWN 178
#define KEY_KPLEFTPAREN 179 #define KEY_KPLEFTPAREN 179
#define KEY_KPRIGHTPAREN 180 #define KEY_KPRIGHTPAREN 180
#define KEY_NEW 181
#define KEY_REDO 182
#define KEY_F13 183 #define KEY_F13 183
#define KEY_F14 184 #define KEY_F14 184
...@@ -335,6 +337,12 @@ struct input_absinfo { ...@@ -335,6 +337,12 @@ struct input_absinfo {
#define KEY_KBDILLUMDOWN 229 #define KEY_KBDILLUMDOWN 229
#define KEY_KBDILLUMUP 230 #define KEY_KBDILLUMUP 230
#define KEY_SEND 231
#define KEY_REPLY 232
#define KEY_FORWARDMAIL 233
#define KEY_SAVE 234
#define KEY_DOCUMENTS 235
#define KEY_UNKNOWN 240 #define KEY_UNKNOWN 240
#define BTN_MISC 0x100 #define BTN_MISC 0x100
......
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