* the Free Software Foundation.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#define psmouse_fmt(fmt) fmt
+
#include <linux/delay.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include "synaptics.h"
#include "logips2pp.h"
#include "alps.h"
+#include "hgpk.h"
#include "lifebook.h"
#include "trackpoint.h"
#include "touchkit_ps2.h"
+#include "elantech.h"
+#include "sentelic.h"
#define DRIVER_DESC "PS/2 mouse driver"
MODULE_LICENSE("GPL");
static unsigned int psmouse_max_proto = PSMOUSE_AUTO;
-static int psmouse_set_maxproto(const char *val, struct kernel_param *kp);
-static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp);
+static int psmouse_set_maxproto(const char *val, const struct kernel_param *);
+static int psmouse_get_maxproto(char *buffer, const struct kernel_param *kp);
+static struct kernel_param_ops param_ops_proto_abbrev = {
+ .set = psmouse_set_maxproto,
+ .get = psmouse_get_maxproto,
+};
#define param_check_proto_abbrev(name, p) __param_check(name, p, unsigned int)
-#define param_set_proto_abbrev psmouse_set_maxproto
-#define param_get_proto_abbrev psmouse_get_maxproto
module_param_named(proto, psmouse_max_proto, proto_abbrev, 0644);
MODULE_PARM_DESC(proto, "Highest protocol extension to probe (bare, imps, exps, any). Useful for KVM switches.");
module_param_named(rate, psmouse_rate, uint, 0644);
MODULE_PARM_DESC(rate, "Report rate, in reports per second.");
-static unsigned int psmouse_smartscroll = 1;
+static bool psmouse_smartscroll = 1;
module_param_named(smartscroll, psmouse_smartscroll, bool, 0644);
MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled.");
struct psmouse_protocol {
enum psmouse_type type;
+ bool maxproto;
+ bool ignore_parity; /* Protocol should ignore parity errors from KBC */
const char *name;
const char *alias;
- int maxproto;
- int (*detect)(struct psmouse *, int);
+ int (*detect)(struct psmouse *, bool);
int (*init)(struct psmouse *);
};
* relevant events to the input module once full packet has arrived.
*/
-static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
+psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
{
struct input_dev *dev = psmouse->dev;
unsigned char *packet = psmouse->packet;
if (psmouse->type == PSMOUSE_IMEX) {
switch (packet[3] & 0xC0) {
- case 0x80: /* vertical scroll on IntelliMouse Explorer 4.0 */
- input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31));
- break;
- case 0x40: /* horizontal scroll on IntelliMouse Explorer 4.0 */
- input_report_rel(dev, REL_HWHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31));
- break;
- case 0x00:
- case 0xC0:
- input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 8) - (int) (packet[3] & 7));
- input_report_key(dev, BTN_SIDE, (packet[3] >> 4) & 1);
- input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1);
- break;
+ case 0x80: /* vertical scroll on IntelliMouse Explorer 4.0 */
+ input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31));
+ break;
+ case 0x40: /* horizontal scroll on IntelliMouse Explorer 4.0 */
+ input_report_rel(dev, REL_HWHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31));
+ break;
+ case 0x00:
+ case 0xC0:
+ input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 8) - (int) (packet[3] & 7));
+ input_report_key(dev, BTN_SIDE, (packet[3] >> 4) & 1);
+ input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1);
+ break;
}
}
}
/*
+ * Cortron PS2 Trackball reports SIDE button on the 4th bit of the first
+ * byte.
+ */
+ if (psmouse->type == PSMOUSE_CORTRON) {
+ input_report_key(dev, BTN_SIDE, (packet[0] >> 3) & 1);
+ packet[0] |= 0x08;
+ }
+
+/*
* Generic PS/2 Mouse
*/
return PSMOUSE_FULL_PACKET;
}
+void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work,
+ unsigned long delay)
+{
+ queue_delayed_work(kpsmoused_wq, work, delay);
+}
+
/*
* __psmouse_set_state() sets new psmouse state and resets all flags.
*/
static inline void __psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
{
psmouse->state = new_state;
- psmouse->pktcnt = psmouse->out_of_sync = 0;
+ psmouse->pktcnt = psmouse->out_of_sync_cnt = 0;
psmouse->ps2dev.flags = 0;
psmouse->last = jiffies;
}
* is not a concern.
*/
-static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
+void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
{
serio_pause_rx(psmouse->ps2dev.serio);
__psmouse_set_state(psmouse, new_state);
psmouse_ret_t rc = psmouse->protocol_handler(psmouse);
switch (rc) {
- case PSMOUSE_BAD_DATA:
- if (psmouse->state == PSMOUSE_ACTIVATED) {
- printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n",
- psmouse->name, psmouse->phys, psmouse->pktcnt);
- if (++psmouse->out_of_sync == psmouse->resetafter) {
- __psmouse_set_state(psmouse, PSMOUSE_IGNORE);
- printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n");
- serio_reconnect(psmouse->ps2dev.serio);
- return -1;
- }
+ case PSMOUSE_BAD_DATA:
+ if (psmouse->state == PSMOUSE_ACTIVATED) {
+ psmouse_warn(psmouse,
+ "%s at %s lost sync at byte %d\n",
+ psmouse->name, psmouse->phys,
+ psmouse->pktcnt);
+ if (++psmouse->out_of_sync_cnt == psmouse->resetafter) {
+ __psmouse_set_state(psmouse, PSMOUSE_IGNORE);
+ psmouse_notice(psmouse,
+ "issuing reconnect request\n");
+ serio_reconnect(psmouse->ps2dev.serio);
+ return -1;
}
- psmouse->pktcnt = 0;
- break;
-
- case PSMOUSE_FULL_PACKET:
- psmouse->pktcnt = 0;
- if (psmouse->out_of_sync) {
- psmouse->out_of_sync = 0;
- printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n",
+ }
+ psmouse->pktcnt = 0;
+ break;
+
+ case PSMOUSE_FULL_PACKET:
+ psmouse->pktcnt = 0;
+ if (psmouse->out_of_sync_cnt) {
+ psmouse->out_of_sync_cnt = 0;
+ psmouse_notice(psmouse,
+ "%s at %s - driver resynced.\n",
psmouse->name, psmouse->phys);
- }
- break;
+ }
+ break;
- case PSMOUSE_GOOD_DATA:
- break;
+ case PSMOUSE_GOOD_DATA:
+ break;
}
return 0;
}
if (psmouse->state == PSMOUSE_IGNORE)
goto out;
- if (flags & (SERIO_PARITY|SERIO_TIMEOUT)) {
+ if (unlikely((flags & SERIO_TIMEOUT) ||
+ ((flags & SERIO_PARITY) && !psmouse->ignore_parity))) {
+
if (psmouse->state == PSMOUSE_ACTIVATED)
- printk(KERN_WARNING "psmouse.c: bad data from KBC -%s%s\n",
- flags & SERIO_TIMEOUT ? " timeout" : "",
- flags & SERIO_PARITY ? " bad parity" : "");
+ psmouse_warn(psmouse,
+ "bad data from KBC -%s%s\n",
+ flags & SERIO_TIMEOUT ? " timeout" : "",
+ flags & SERIO_PARITY ? " bad parity" : "");
ps2_cmd_aborted(&psmouse->ps2dev);
goto out;
}
if (psmouse->state == PSMOUSE_ACTIVATED &&
psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) {
- printk(KERN_INFO "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n",
- psmouse->name, psmouse->phys, psmouse->pktcnt);
+ psmouse_info(psmouse, "%s at %s lost synchronization, throwing %d bytes away.\n",
+ psmouse->name, psmouse->phys, psmouse->pktcnt);
psmouse->badbyte = psmouse->packet[0];
__psmouse_set_state(psmouse, PSMOUSE_RESYNCING);
- queue_work(kpsmoused_wq, &psmouse->resync_work);
+ psmouse_queue_work(psmouse, &psmouse->resync_work, 0);
goto out;
}
goto out;
}
- if (psmouse->packet[1] == PSMOUSE_RET_ID) {
+ if (psmouse->packet[1] == PSMOUSE_RET_ID ||
+ (psmouse->type == PSMOUSE_HGPK &&
+ psmouse->packet[1] == PSMOUSE_RET_BAT)) {
__psmouse_set_state(psmouse, PSMOUSE_IGNORE);
serio_reconnect(serio);
goto out;
time_after(jiffies, psmouse->last + psmouse->resync_time * HZ)) {
psmouse->badbyte = psmouse->packet[0];
__psmouse_set_state(psmouse, PSMOUSE_RESYNCING);
- queue_work(kpsmoused_wq, &psmouse->resync_work);
+ psmouse_queue_work(psmouse, &psmouse->resync_work, 0);
goto out;
}
return 0;
}
+/*
+ * Here we set the mouse resolution.
+ */
+
+void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution)
+{
+ static const unsigned char params[] = { 0, 1, 2, 2, 3 };
+ unsigned char p;
+
+ if (resolution == 0 || resolution > 200)
+ resolution = 200;
+
+ p = params[resolution / 50];
+ ps2_command(&psmouse->ps2dev, &p, PSMOUSE_CMD_SETRES);
+ psmouse->resolution = 25 << p;
+}
+
+/*
+ * Here we set the mouse report rate.
+ */
+
+static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate)
+{
+ static const unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 };
+ unsigned char r;
+ int i = 0;
+
+ while (rates[i] > rate) i++;
+ r = rates[i];
+ ps2_command(&psmouse->ps2dev, &r, PSMOUSE_CMD_SETRATE);
+ psmouse->rate = r;
+}
+
+/*
+ * psmouse_poll() - default poll handler. Everyone except for ALPS uses it.
+ */
+
+static int psmouse_poll(struct psmouse *psmouse)
+{
+ return ps2_command(&psmouse->ps2dev, psmouse->packet,
+ PSMOUSE_CMD_POLL | (psmouse->pktsize << 8));
+}
+
/*
* Genius NetMouse magic init.
*/
-static int genius_detect(struct psmouse *psmouse, int set_properties)
+static int genius_detect(struct psmouse *psmouse, bool set_properties)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[4];
return -1;
if (set_properties) {
- set_bit(BTN_EXTRA, psmouse->dev->keybit);
- set_bit(BTN_SIDE, psmouse->dev->keybit);
- set_bit(REL_WHEEL, psmouse->dev->relbit);
+ __set_bit(BTN_MIDDLE, psmouse->dev->keybit);
+ __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 = "Mouse";
/*
* IntelliMouse magic init.
*/
-static int intellimouse_detect(struct psmouse *psmouse, int set_properties)
+static int intellimouse_detect(struct psmouse *psmouse, bool set_properties)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[2];
return -1;
if (set_properties) {
- set_bit(BTN_MIDDLE, psmouse->dev->keybit);
- set_bit(REL_WHEEL, psmouse->dev->relbit);
+ __set_bit(BTN_MIDDLE, psmouse->dev->keybit);
+ __set_bit(REL_WHEEL, psmouse->dev->relbit);
- if (!psmouse->vendor) psmouse->vendor = "Generic";
- if (!psmouse->name) psmouse->name = "Wheel Mouse";
+ if (!psmouse->vendor)
+ psmouse->vendor = "Generic";
+ if (!psmouse->name)
+ psmouse->name = "Wheel Mouse";
psmouse->pktsize = 4;
}
/*
* Try IntelliMouse/Explorer magic init.
*/
-static int im_explorer_detect(struct psmouse *psmouse, int set_properties)
+static int im_explorer_detect(struct psmouse *psmouse, bool set_properties)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[2];
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
if (set_properties) {
- set_bit(BTN_MIDDLE, psmouse->dev->keybit);
- set_bit(REL_WHEEL, psmouse->dev->relbit);
- set_bit(REL_HWHEEL, psmouse->dev->relbit);
- set_bit(BTN_SIDE, psmouse->dev->keybit);
- set_bit(BTN_EXTRA, psmouse->dev->keybit);
-
- if (!psmouse->vendor) psmouse->vendor = "Generic";
- if (!psmouse->name) psmouse->name = "Explorer Mouse";
+ __set_bit(BTN_MIDDLE, psmouse->dev->keybit);
+ __set_bit(REL_WHEEL, psmouse->dev->relbit);
+ __set_bit(REL_HWHEEL, psmouse->dev->relbit);
+ __set_bit(BTN_SIDE, psmouse->dev->keybit);
+ __set_bit(BTN_EXTRA, psmouse->dev->keybit);
+
+ if (!psmouse->vendor)
+ psmouse->vendor = "Generic";
+ if (!psmouse->name)
+ psmouse->name = "Explorer Mouse";
psmouse->pktsize = 4;
}
/*
* Kensington ThinkingMouse / ExpertMouse magic init.
*/
-static int thinking_detect(struct psmouse *psmouse, int set_properties)
+static int thinking_detect(struct psmouse *psmouse, bool set_properties)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[2];
return -1;
if (set_properties) {
- set_bit(BTN_EXTRA, psmouse->dev->keybit);
+ __set_bit(BTN_MIDDLE, psmouse->dev->keybit);
+ __set_bit(BTN_EXTRA, psmouse->dev->keybit);
psmouse->vendor = "Kensington";
psmouse->name = "ThinkingMouse";
/*
* Bare PS/2 protocol "detection". Always succeeds.
*/
-static int ps2bare_detect(struct psmouse *psmouse, int set_properties)
+static int ps2bare_detect(struct psmouse *psmouse, bool set_properties)
{
if (set_properties) {
- if (!psmouse->vendor) psmouse->vendor = "Generic";
- if (!psmouse->name) psmouse->name = "Mouse";
+ if (!psmouse->vendor)
+ psmouse->vendor = "Generic";
+ if (!psmouse->name)
+ psmouse->name = "Mouse";
+
+/*
+ * We have no way of figuring true number of buttons so let's
+ * assume that the device has 3.
+ */
+ __set_bit(BTN_MIDDLE, psmouse->dev->keybit);
}
return 0;
}
+/*
+ * Cortron PS/2 protocol detection. There's no special way to detect it, so it
+ * must be forced by sysfs protocol writing.
+ */
+static int cortron_detect(struct psmouse *psmouse, bool set_properties)
+{
+ if (set_properties) {
+ psmouse->vendor = "Cortron";
+ psmouse->name = "PS/2 Trackball";
+
+ __set_bit(BTN_MIDDLE, psmouse->dev->keybit);
+ __set_bit(BTN_SIDE, psmouse->dev->keybit);
+ }
+
+ return 0;
+}
+
+/*
+ * Apply default settings to the psmouse structure. Most of them will
+ * be overridden by individual protocol initialization routines.
+ */
+
+static void psmouse_apply_defaults(struct psmouse *psmouse)
+{
+ struct input_dev *input_dev = psmouse->dev;
+
+ memset(input_dev->evbit, 0, sizeof(input_dev->evbit));
+ memset(input_dev->keybit, 0, sizeof(input_dev->keybit));
+ memset(input_dev->relbit, 0, sizeof(input_dev->relbit));
+ memset(input_dev->absbit, 0, sizeof(input_dev->absbit));
+ memset(input_dev->mscbit, 0, sizeof(input_dev->mscbit));
+
+ __set_bit(EV_KEY, input_dev->evbit);
+ __set_bit(EV_REL, input_dev->evbit);
+
+ __set_bit(BTN_LEFT, input_dev->keybit);
+ __set_bit(BTN_RIGHT, input_dev->keybit);
+
+ __set_bit(REL_X, input_dev->relbit);
+ __set_bit(REL_Y, input_dev->relbit);
+
+ psmouse->set_rate = psmouse_set_rate;
+ psmouse->set_resolution = psmouse_set_resolution;
+ psmouse->poll = psmouse_poll;
+ psmouse->protocol_handler = psmouse_process_byte;
+ psmouse->pktsize = 3;
+ psmouse->reconnect = NULL;
+ psmouse->disconnect = NULL;
+ psmouse->cleanup = NULL;
+ psmouse->pt_activate = NULL;
+ psmouse->pt_deactivate = NULL;
+}
+
+/*
+ * Apply default settings to the psmouse structure and call specified
+ * protocol detection or initialization routine.
+ */
+static int psmouse_do_detect(int (*detect)(struct psmouse *psmouse,
+ bool set_properties),
+ struct psmouse *psmouse, bool set_properties)
+{
+ if (set_properties)
+ psmouse_apply_defaults(psmouse);
+
+ return detect(psmouse, set_properties);
+}
/*
* psmouse_extensions() probes for any extensions to the basic PS/2 protocol
*/
static int psmouse_extensions(struct psmouse *psmouse,
- unsigned int max_proto, int set_properties)
+ unsigned int max_proto, bool set_properties)
{
- int synaptics_hardware = 0;
+ bool synaptics_hardware = false;
/*
* We always check for lifebook because it does not disturb mouse
* (it only checks DMI information).
*/
- if (lifebook_detect(psmouse, set_properties) == 0) {
+ if (psmouse_do_detect(lifebook_detect, psmouse, set_properties) == 0) {
if (max_proto > PSMOUSE_IMEX) {
if (!set_properties || lifebook_init(psmouse) == 0)
return PSMOUSE_LIFEBOOK;
* upsets the thinkingmouse).
*/
- if (max_proto > PSMOUSE_IMEX && thinking_detect(psmouse, set_properties) == 0)
+ if (max_proto > PSMOUSE_IMEX &&
+ psmouse_do_detect(thinking_detect, psmouse, set_properties) == 0) {
return PSMOUSE_THINKPS;
+ }
/*
* Try Synaptics TouchPad. Note that probing is done even if Synaptics protocol
* support is disabled in config - we need to know if it is synaptics so we
* can reset it properly after probing for intellimouse.
*/
- if (max_proto > PSMOUSE_PS2 && synaptics_detect(psmouse, set_properties) == 0) {
- synaptics_hardware = 1;
+ if (max_proto > PSMOUSE_PS2 &&
+ psmouse_do_detect(synaptics_detect, psmouse, set_properties) == 0) {
+ synaptics_hardware = true;
if (max_proto > PSMOUSE_IMEX) {
- if (!set_properties || synaptics_init(psmouse) == 0)
+/*
+ * Try activating protocol, but check if support is enabled first, since
+ * we try detecting Synaptics even when protocol is disabled.
+ */
+ if (synaptics_supported() &&
+ (!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
*/
if (max_proto > PSMOUSE_IMEX) {
ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
- if (alps_detect(psmouse, set_properties) == 0) {
+ if (psmouse_do_detect(alps_detect,
+ psmouse, set_properties) == 0) {
if (!set_properties || alps_init(psmouse) == 0)
return PSMOUSE_ALPS;
/*
}
}
- if (max_proto > PSMOUSE_IMEX) {
+/*
+ * Try OLPC HGPK touchpad.
+ */
+ if (max_proto > PSMOUSE_IMEX &&
+ psmouse_do_detect(hgpk_detect, psmouse, set_properties) == 0) {
+ if (!set_properties || hgpk_init(psmouse) == 0)
+ return PSMOUSE_HGPK;
+/*
+ * Init failed, try basic relative protocols
+ */
+ max_proto = PSMOUSE_IMEX;
+ }
+
+/*
+ * Try Elantech touchpad.
+ */
+ if (max_proto > PSMOUSE_IMEX &&
+ psmouse_do_detect(elantech_detect, psmouse, set_properties) == 0) {
+ if (!set_properties || elantech_init(psmouse) == 0)
+ return PSMOUSE_ELANTECH;
+/*
+ * Init failed, try basic relative protocols
+ */
+ max_proto = PSMOUSE_IMEX;
+ }
- if (genius_detect(psmouse, set_properties) == 0)
+ if (max_proto > PSMOUSE_IMEX) {
+ if (psmouse_do_detect(genius_detect,
+ psmouse, set_properties) == 0)
return PSMOUSE_GENPS;
- if (ps2pp_init(psmouse, set_properties) == 0)
+ if (psmouse_do_detect(ps2pp_init,
+ psmouse, set_properties) == 0)
return PSMOUSE_PS2PP;
- if (trackpoint_detect(psmouse, set_properties) == 0)
+ if (psmouse_do_detect(trackpoint_detect,
+ psmouse, set_properties) == 0)
return PSMOUSE_TRACKPOINT;
- if (touchkit_ps2_detect(psmouse, set_properties) == 0)
+ if (psmouse_do_detect(touchkit_ps2_detect,
+ psmouse, set_properties) == 0)
return PSMOUSE_TOUCHKIT_PS2;
}
/*
+ * Try Finger Sensing Pad. We do it here because its probe upsets
+ * Trackpoint devices (causing TP_READ_ID command to time out).
+ */
+ if (max_proto > PSMOUSE_IMEX) {
+ if (psmouse_do_detect(fsp_detect,
+ psmouse, set_properties) == 0) {
+ if (!set_properties || fsp_init(psmouse) == 0)
+ return PSMOUSE_FSP;
+/*
+ * Init failed, try basic relative protocols
+ */
+ max_proto = PSMOUSE_IMEX;
+ }
+ }
+
+/*
* Reset to defaults in case the device got confused by extended
- * protocol probes. Note that we do full reset becuase some mice
- * put themselves to sleep when see PSMOUSE_RESET_DIS.
+ * protocol probes. Note that we follow up with full reset because
+ * some mice put themselves to sleep when they see PSMOUSE_RESET_DIS.
*/
+ ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
psmouse_reset(psmouse);
- if (max_proto >= PSMOUSE_IMEX && im_explorer_detect(psmouse, set_properties) == 0)
+ if (max_proto >= PSMOUSE_IMEX &&
+ psmouse_do_detect(im_explorer_detect,
+ psmouse, set_properties) == 0) {
return PSMOUSE_IMEX;
+ }
- if (max_proto >= PSMOUSE_IMPS && intellimouse_detect(psmouse, set_properties) == 0)
+ if (max_proto >= PSMOUSE_IMPS &&
+ psmouse_do_detect(intellimouse_detect,
+ psmouse, set_properties) == 0) {
return PSMOUSE_IMPS;
+ }
/*
* Okay, all failed, we have a standard mouse here. The number of the buttons
* is still a question, though. We assume 3.
*/
- ps2bare_detect(psmouse, set_properties);
+ psmouse_do_detect(ps2bare_detect, psmouse, set_properties);
if (synaptics_hardware) {
/*
.type = PSMOUSE_PS2,
.name = "PS/2",
.alias = "bare",
- .maxproto = 1,
+ .maxproto = true,
+ .ignore_parity = true,
.detect = ps2bare_detect,
},
#ifdef CONFIG_MOUSE_PS2_LOGIPS2PP
.type = PSMOUSE_IMPS,
.name = "ImPS/2",
.alias = "imps",
- .maxproto = 1,
+ .maxproto = true,
+ .ignore_parity = true,
.detect = intellimouse_detect,
},
{
.type = PSMOUSE_IMEX,
.name = "ImExPS/2",
.alias = "exps",
- .maxproto = 1,
+ .maxproto = true,
+ .ignore_parity = true,
.detect = im_explorer_detect,
},
#ifdef CONFIG_MOUSE_PS2_SYNAPTICS
.detect = synaptics_detect,
.init = synaptics_init,
},
+ {
+ .type = PSMOUSE_SYNAPTICS_RELATIVE,
+ .name = "SynRelPS/2",
+ .alias = "synaptics-relative",
+ .detect = synaptics_detect,
+ .init = synaptics_init_relative,
+ },
#endif
#ifdef CONFIG_MOUSE_PS2_ALPS
{
.detect = touchkit_ps2_detect,
},
#endif
+#ifdef CONFIG_MOUSE_PS2_OLPC
+ {
+ .type = PSMOUSE_HGPK,
+ .name = "OLPC HGPK",
+ .alias = "hgpk",
+ .detect = hgpk_detect,
+ },
+#endif
+#ifdef CONFIG_MOUSE_PS2_ELANTECH
+ {
+ .type = PSMOUSE_ELANTECH,
+ .name = "ETPS/2",
+ .alias = "elantech",
+ .detect = elantech_detect,
+ .init = elantech_init,
+ },
+#endif
+#ifdef CONFIG_MOUSE_PS2_SENTELIC
+ {
+ .type = PSMOUSE_FSP,
+ .name = "FSPPS/2",
+ .alias = "fsp",
+ .detect = fsp_detect,
+ .init = fsp_init,
+ },
+#endif
+ {
+ .type = PSMOUSE_CORTRON,
+ .name = "CortronPS/2",
+ .alias = "cortps",
+ .detect = cortron_detect,
+ },
{
.type = PSMOUSE_AUTO,
.name = "auto",
.alias = "any",
- .maxproto = 1,
+ .maxproto = true,
},
};
*/
if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_DIS))
- printk(KERN_WARNING "psmouse.c: Failed to reset mouse on %s\n", ps2dev->serio->phys);
+ psmouse_warn(psmouse, "Failed to reset mouse on %s\n",
+ ps2dev->serio->phys);
return 0;
}
/*
- * Here we set the mouse resolution.
- */
-
-void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution)
-{
- static const unsigned char params[] = { 0, 1, 2, 2, 3 };
- unsigned char p;
-
- if (resolution == 0 || resolution > 200)
- resolution = 200;
-
- p = params[resolution / 50];
- ps2_command(&psmouse->ps2dev, &p, PSMOUSE_CMD_SETRES);
- psmouse->resolution = 25 << p;
-}
-
-/*
- * Here we set the mouse report rate.
- */
-
-static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate)
-{
- static const unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 };
- unsigned char r;
- int i = 0;
-
- while (rates[i] > rate) i++;
- r = rates[i];
- ps2_command(&psmouse->ps2dev, &r, PSMOUSE_CMD_SETRATE);
- psmouse->rate = r;
-}
-
-/*
* psmouse_initialize() initializes the mouse to a sane state.
*/
* psmouse_activate() enables the mouse so that we get motion reports from it.
*/
-static void psmouse_activate(struct psmouse *psmouse)
+int psmouse_activate(struct psmouse *psmouse)
{
- if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE))
- printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n",
- psmouse->ps2dev.serio->phys);
+ if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) {
+ psmouse_warn(psmouse, "Failed to enable mouse on %s\n",
+ psmouse->ps2dev.serio->phys);
+ return -1;
+ }
psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
+ return 0;
}
-
/*
* psmouse_deactivate() puts the mouse into poll mode so that we don't get motion
- * reports from it unless we explicitely request it.
+ * reports from it unless we explicitly request it.
*/
-static void psmouse_deactivate(struct psmouse *psmouse)
+int psmouse_deactivate(struct psmouse *psmouse)
{
- if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE))
- printk(KERN_WARNING "psmouse.c: Failed to deactivate mouse on %s\n",
- psmouse->ps2dev.serio->phys);
+ if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE)) {
+ psmouse_warn(psmouse, "Failed to deactivate mouse on %s\n",
+ psmouse->ps2dev.serio->phys);
+ return -1;
+ }
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
-}
-
-/*
- * psmouse_poll() - default poll hanlder. Everyone except for ALPS uses it.
- */
-
-static int psmouse_poll(struct psmouse *psmouse)
-{
- return ps2_command(&psmouse->ps2dev, psmouse->packet,
- PSMOUSE_CMD_POLL | (psmouse->pktsize << 8));
+ return 0;
}
static void psmouse_resync(struct work_struct *work)
{
struct psmouse *parent = NULL, *psmouse =
- container_of(work, struct psmouse, resync_work);
+ container_of(work, struct psmouse, resync_work.work);
struct serio *serio = psmouse->ps2dev.serio;
psmouse_ret_t rc = PSMOUSE_GOOD_DATA;
- int failed = 0, enabled = 0;
+ bool failed = false, enabled = false;
int i;
mutex_lock(&psmouse_mutex);
if (ps2_sendbyte(&psmouse->ps2dev, PSMOUSE_CMD_DISABLE, 20)) {
if (psmouse->num_resyncs < 3 || psmouse->acks_disable_command)
- failed = 1;
+ failed = true;
} else
- psmouse->acks_disable_command = 1;
+ psmouse->acks_disable_command = true;
/*
* Poll the mouse. If it was reset the packet will be shorter than
*/
if (!failed) {
if (psmouse->poll(psmouse))
- failed = 1;
+ failed = true;
else {
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
for (i = 0; i < psmouse->pktsize; i++) {
break;
}
if (rc != PSMOUSE_FULL_PACKET)
- failed = 1;
+ failed = true;
psmouse_set_state(psmouse, PSMOUSE_RESYNCING);
}
}
*/
for (i = 0; i < 5; i++) {
if (!ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) {
- enabled = 1;
+ enabled = true;
break;
}
msleep(200);
}
if (!enabled) {
- printk(KERN_WARNING "psmouse.c: failed to re-enable mouse on %s\n",
- psmouse->ps2dev.serio->phys);
- failed = 1;
+ psmouse_warn(psmouse, "failed to re-enable mouse on %s\n",
+ psmouse->ps2dev.serio->phys);
+ failed = true;
}
if (failed) {
psmouse_set_state(psmouse, PSMOUSE_IGNORE);
- printk(KERN_INFO "psmouse.c: resync failed, issuing reconnect request\n");
+ psmouse_info(psmouse,
+ "resync failed, issuing reconnect request\n");
serio_reconnect(serio);
} else
psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
psmouse_deactivate(parent);
}
- psmouse_deactivate(psmouse);
+ psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
+
+ /*
+ * Disable stream mode so cleanup routine can proceed undisturbed.
+ */
+ if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE))
+ psmouse_warn(psmouse, "Failed to disable mouse on %s\n",
+ psmouse->ps2dev.serio->phys);
if (psmouse->cleanup)
psmouse->cleanup(psmouse);
- psmouse_reset(psmouse);
+/*
+ * Reset the mouse to defaults (bare PS/2 protocol).
+ */
+ ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
/*
* Some boxes, such as HP nx7400, get terribly confused if mouse
mutex_unlock(&psmouse_mutex);
}
-static int psmouse_switch_protocol(struct psmouse *psmouse, const struct psmouse_protocol *proto)
+static int psmouse_switch_protocol(struct psmouse *psmouse,
+ const struct psmouse_protocol *proto)
{
+ const struct psmouse_protocol *selected_proto;
struct input_dev *input_dev = psmouse->dev;
input_dev->dev.parent = &psmouse->ps2dev.serio->dev;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
- input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
- input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
-
- psmouse->set_rate = psmouse_set_rate;
- psmouse->set_resolution = psmouse_set_resolution;
- psmouse->poll = psmouse_poll;
- psmouse->protocol_handler = psmouse_process_byte;
- psmouse->pktsize = 3;
-
if (proto && (proto->detect || proto->init)) {
- if (proto->detect && proto->detect(psmouse, 1) < 0)
+ psmouse_apply_defaults(psmouse);
+
+ if (proto->detect && proto->detect(psmouse, true) < 0)
return -1;
if (proto->init && proto->init(psmouse) < 0)
return -1;
psmouse->type = proto->type;
+ selected_proto = proto;
+ } else {
+ psmouse->type = psmouse_extensions(psmouse,
+ psmouse_max_proto, true);
+ selected_proto = psmouse_protocol_by_type(psmouse->type);
}
- else
- psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1);
+
+ psmouse->ignore_parity = selected_proto->ignore_parity;
/*
* If mouse's packet size is 3 there is no point in polling the
psmouse->resync_time = 0;
snprintf(psmouse->devname, sizeof(psmouse->devname), "%s %s %s",
- psmouse_protocol_by_type(psmouse->type)->name, psmouse->vendor, psmouse->name);
+ selected_proto->name, psmouse->vendor, psmouse->name);
input_dev->name = psmouse->devname;
input_dev->phys = psmouse->phys;
goto err_free;
ps2_init(&psmouse->ps2dev, serio);
- INIT_WORK(&psmouse->resync_work, psmouse_resync);
+ INIT_DELAYED_WORK(&psmouse->resync_work, psmouse_resync);
psmouse->dev = input_dev;
snprintf(psmouse->phys, sizeof(psmouse->phys), "%s/input0", serio->phys);
err_pt_deactivate:
if (parent && parent->pt_deactivate)
parent->pt_deactivate(parent);
+ input_unregister_device(psmouse->dev);
+ input_dev = NULL; /* so we don't try to free it below */
err_protocol_disconnect:
if (psmouse->disconnect)
psmouse->disconnect(psmouse);
struct psmouse *psmouse = serio_get_drvdata(serio);
struct psmouse *parent = NULL;
struct serio_driver *drv = serio->drv;
+ unsigned char type;
int rc = -1;
if (!drv || !psmouse) {
- printk(KERN_DEBUG "psmouse: reconnect request, but serio is disconnected, ignoring...\n");
+ psmouse_dbg(psmouse,
+ "reconnect request, but serio is disconnected, ignoring...\n");
return -1;
}
if (psmouse->reconnect) {
if (psmouse->reconnect(psmouse))
goto out;
- } else if (psmouse_probe(psmouse) < 0 ||
- psmouse->type != psmouse_extensions(psmouse, psmouse_max_proto, 0))
- goto out;
+ } else {
+ psmouse_reset(psmouse);
+
+ if (psmouse_probe(psmouse) < 0)
+ goto out;
+
+ type = psmouse_extensions(psmouse, psmouse_max_proto, false);
+ if (psmouse->type != type)
+ goto out;
+ }
- /* ok, the device type (and capabilities) match the old one,
- * we can continue using it, complete intialization
+ /*
+ * OK, the device type (and capabilities) match the old one,
+ * we can continue using it, complete initialization
*/
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
struct serio *serio = to_serio_port(dev);
struct psmouse_attribute *attr = to_psmouse_attr(devattr);
struct psmouse *psmouse;
- int retval;
-
- retval = serio_pin_driver(serio);
- if (retval)
- return retval;
-
- if (serio->drv != &psmouse_drv) {
- retval = -ENODEV;
- goto out;
- }
psmouse = serio_get_drvdata(serio);
- retval = attr->show(psmouse, attr->data, buf);
-
-out:
- serio_unpin_driver(serio);
- return retval;
+ return attr->show(psmouse, attr->data, buf);
}
ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *devattr,
struct psmouse *psmouse, *parent = NULL;
int retval;
- retval = serio_pin_driver(serio);
- if (retval)
- return retval;
-
- if (serio->drv != &psmouse_drv) {
- retval = -ENODEV;
- goto out_unpin;
- }
-
retval = mutex_lock_interruptible(&psmouse_mutex);
if (retval)
- goto out_unpin;
+ goto out;
psmouse = serio_get_drvdata(serio);
- if (psmouse->state == PSMOUSE_IGNORE) {
- retval = -ENODEV;
- goto out_unlock;
- }
+ if (attr->protect) {
+ if (psmouse->state == PSMOUSE_IGNORE) {
+ retval = -ENODEV;
+ goto out_unlock;
+ }
- if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
- parent = serio_get_drvdata(serio->parent);
- psmouse_deactivate(parent);
- }
+ if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
+ parent = serio_get_drvdata(serio->parent);
+ psmouse_deactivate(parent);
+ }
- psmouse_deactivate(psmouse);
+ psmouse_deactivate(psmouse);
+ }
retval = attr->set(psmouse, attr->data, buf, count);
- if (retval != -ENODEV)
- psmouse_activate(psmouse);
+ if (attr->protect) {
+ if (retval != -ENODEV)
+ psmouse_activate(psmouse);
- if (parent)
- psmouse_activate(parent);
+ if (parent)
+ psmouse_activate(parent);
+ }
out_unlock:
mutex_unlock(&psmouse_mutex);
- out_unpin:
- serio_unpin_driver(serio);
+ out:
return retval;
}
static ssize_t psmouse_set_int_attr(struct psmouse *psmouse, void *offset, const char *buf, size_t count)
{
unsigned int *field = (unsigned int *)((char *)psmouse + (size_t)offset);
- unsigned long value;
- char *rest;
-
- value = simple_strtoul(buf, &rest, 10);
- if (*rest)
- return -EINVAL;
+ unsigned int value;
+ int err;
- if ((unsigned int)value != value)
- return -EINVAL;
+ err = kstrtouint(buf, 10, &value);
+ if (err)
+ return err;
*field = value;
if (!new_dev)
return -ENOMEM;
- while (serio->child) {
+ while (!list_empty(&serio->children)) {
if (++retry > 3) {
- printk(KERN_WARNING "psmouse: failed to destroy child port, protocol change aborted.\n");
+ psmouse_warn(psmouse,
+ "failed to destroy children ports, protocol change aborted.\n");
input_free_device(new_dev);
return -EIO;
}
mutex_unlock(&psmouse_mutex);
- serio_unpin_driver(serio);
serio_unregister_child_port(serio);
- serio_pin_driver_uninterruptible(serio);
mutex_lock(&psmouse_mutex);
if (serio->drv != &psmouse_drv) {
static ssize_t psmouse_attr_set_rate(struct psmouse *psmouse, void *data, const char *buf, size_t count)
{
- unsigned long value;
- char *rest;
+ unsigned int value;
+ int err;
- value = simple_strtoul(buf, &rest, 10);
- if (*rest)
- return -EINVAL;
+ err = kstrtouint(buf, 10, &value);
+ if (err)
+ return err;
psmouse->set_rate(psmouse, value);
return count;
static ssize_t psmouse_attr_set_resolution(struct psmouse *psmouse, void *data, const char *buf, size_t count)
{
- unsigned long value;
- char *rest;
+ unsigned int value;
+ int err;
- value = simple_strtoul(buf, &rest, 10);
- if (*rest)
- return -EINVAL;
+ err = kstrtouint(buf, 10, &value);
+ if (err)
+ return err;
psmouse->set_resolution(psmouse, value);
return count;
}
-static int psmouse_set_maxproto(const char *val, struct kernel_param *kp)
+static int psmouse_set_maxproto(const char *val, const struct kernel_param *kp)
{
const struct psmouse_protocol *proto;
return 0;
}
-static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp)
+static int psmouse_get_maxproto(char *buffer, const struct kernel_param *kp)
{
int type = *((unsigned int *)kp->arg);
- return sprintf(buffer, "%s\n", psmouse_protocol_by_type(type)->name);
+ return sprintf(buffer, "%s", psmouse_protocol_by_type(type)->name);
}
static int __init psmouse_init(void)
{
int err;
+ lifebook_module_init();
+ synaptics_module_init();
+ hgpk_module_init();
+
kpsmoused_wq = create_singlethread_workqueue("kpsmoused");
if (!kpsmoused_wq) {
- printk(KERN_ERR "psmouse: failed to create kpsmoused workqueue\n");
+ pr_err("failed to create kpsmoused workqueue\n");
return -ENOMEM;
}