#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"
.attrs = psmouse_attributes,
};
-__obsolete_setup("psmouse_noext");
-__obsolete_setup("psmouse_resolution=");
-__obsolete_setup("psmouse_smartscroll=");
-__obsolete_setup("psmouse_resetafter=");
-__obsolete_setup("psmouse_rate=");
-
/*
* psmouse_mutex protects all operations changing state of mouse
* (connecting, disconnecting, changing rate or resolution via
struct psmouse_protocol {
enum psmouse_type type;
+ bool maxproto;
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, struct pt_regs *regs)
+static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
{
struct input_dev *dev = psmouse->dev;
unsigned char *packet = psmouse->packet;
* Full packet accumulated, process it
*/
- input_regs(dev, regs);
-
/*
* Scroll wheel on IntelliMice, scroll buttons on NetMice
*/
}
/*
+ * 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);
* by calling corresponding protocol handler.
*/
-static int psmouse_handle_byte(struct psmouse *psmouse, struct pt_regs *regs)
+static int psmouse_handle_byte(struct psmouse *psmouse)
{
- psmouse_ret_t rc = psmouse->protocol_handler(psmouse, regs);
+ 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) {
+ if (++psmouse->out_of_sync_cnt == psmouse->resetafter) {
__psmouse_set_state(psmouse, PSMOUSE_IGNORE);
printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n");
serio_reconnect(psmouse->ps2dev.serio);
case PSMOUSE_FULL_PACKET:
psmouse->pktcnt = 0;
- if (psmouse->out_of_sync) {
- psmouse->out_of_sync = 0;
+ if (psmouse->out_of_sync_cnt) {
+ psmouse->out_of_sync_cnt = 0;
printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n",
psmouse->name, psmouse->phys);
}
*/
static irqreturn_t psmouse_interrupt(struct serio *serio,
- unsigned char data, unsigned int flags, struct pt_regs *regs)
+ unsigned char data, unsigned int flags)
{
struct psmouse *psmouse = serio_get_drvdata(serio);
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;
* Not a new device, try processing first byte normally
*/
psmouse->pktcnt = 1;
- if (psmouse_handle_byte(psmouse, regs))
+ if (psmouse_handle_byte(psmouse))
goto out;
psmouse->packet[psmouse->pktcnt++] = data;
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;
}
psmouse->last = jiffies;
- psmouse_handle_byte(psmouse, regs);
+ psmouse_handle_byte(psmouse);
out:
return IRQ_HANDLED;
/*
* 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_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";
/*
* 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];
param[0] = 40;
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
- param[0] = 200;
- ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
- param[0] = 200;
- ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
- param[0] = 60;
- 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);
+ __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";
/*
* 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_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";
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_SIDE, psmouse->dev->keybit);
+ }
+
+ return 0;
+}
/*
* 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 = true;
/*
* We always check for lifebook because it does not disturb mouse
return PSMOUSE_THINKPS;
/*
- * Try Synaptics TouchPad
+ * 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;
+ synaptics_hardware = true;
if (max_proto > PSMOUSE_IMEX) {
if (!set_properties || synaptics_init(psmouse) == 0)
}
}
- if (max_proto > PSMOUSE_IMEX && genius_detect(psmouse, set_properties) == 0)
- return PSMOUSE_GENPS;
+/*
+ * Try OLPC HGPK touchpad.
+ */
+ if (max_proto > PSMOUSE_IMEX &&
+ 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 &&
+ 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;
+ }
+
+/*
+ * Try Finger Sensing Pad
+ */
+ if (max_proto > PSMOUSE_IMEX) {
+ if (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;
+ }
+ }
+
+ if (max_proto > PSMOUSE_IMEX) {
+ if (genius_detect(psmouse, set_properties) == 0)
+ return PSMOUSE_GENPS;
+
+ if (ps2pp_init(psmouse, set_properties) == 0)
+ return PSMOUSE_PS2PP;
- if (max_proto > PSMOUSE_IMEX && ps2pp_init(psmouse, set_properties) == 0)
- return PSMOUSE_PS2PP;
+ if (trackpoint_detect(psmouse, set_properties) == 0)
+ return PSMOUSE_TRACKPOINT;
- if (max_proto > PSMOUSE_IMEX && trackpoint_detect(psmouse, set_properties) == 0)
- return PSMOUSE_TRACKPOINT;
+ if (touchkit_ps2_detect(psmouse, set_properties) == 0)
+ return PSMOUSE_TOUCHKIT_PS2;
+ }
/*
* 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)
.type = PSMOUSE_PS2,
.name = "PS/2",
.alias = "bare",
- .maxproto = 1,
+ .maxproto = true,
.detect = ps2bare_detect,
},
+#ifdef CONFIG_MOUSE_PS2_LOGIPS2PP
{
.type = PSMOUSE_PS2PP,
.name = "PS2++",
.alias = "logitech",
.detect = ps2pp_init,
},
+#endif
{
.type = PSMOUSE_THINKPS,
.name = "ThinkPS/2",
.type = PSMOUSE_IMPS,
.name = "ImPS/2",
.alias = "imps",
- .maxproto = 1,
+ .maxproto = true,
.detect = intellimouse_detect,
},
{
.type = PSMOUSE_IMEX,
.name = "ImExPS/2",
.alias = "exps",
- .maxproto = 1,
+ .maxproto = true,
.detect = im_explorer_detect,
},
+#ifdef CONFIG_MOUSE_PS2_SYNAPTICS
{
.type = PSMOUSE_SYNAPTICS,
.name = "SynPS/2",
.detect = synaptics_detect,
.init = synaptics_init,
},
+#endif
+#ifdef CONFIG_MOUSE_PS2_ALPS
{
.type = PSMOUSE_ALPS,
.name = "AlpsPS/2",
.detect = alps_detect,
.init = alps_init,
},
+#endif
+#ifdef CONFIG_MOUSE_PS2_LIFEBOOK
{
.type = PSMOUSE_LIFEBOOK,
.name = "LBPS/2",
.alias = "lifebook",
.init = lifebook_init,
},
+#endif
+#ifdef CONFIG_MOUSE_PS2_TRACKPOINT
{
.type = PSMOUSE_TRACKPOINT,
.name = "TPPS/2",
.alias = "trackpoint",
.detect = trackpoint_detect,
},
+#endif
+#ifdef CONFIG_MOUSE_PS2_TOUCHKIT
+ {
+ .type = PSMOUSE_TOUCHKIT_PS2,
+ .name = "touchkitPS/2",
+ .alias = "touchkit",
+ .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,
},
};
static void psmouse_initialize(struct psmouse *psmouse)
{
/*
- * We set the mouse into streaming mode.
- */
-
- ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSTREAM);
-
-/*
* We set the mouse report rate, resolution and scaling.
*/
/*
* 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)
* psmouse_resync() attempts to re-validate current protocol.
*/
-static void psmouse_resync(void *p)
+static void psmouse_resync(struct work_struct *work)
{
- struct psmouse *psmouse = p, *parent = NULL;
+ struct psmouse *parent = NULL, *psmouse =
+ 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++) {
psmouse->pktcnt++;
- rc = psmouse->protocol_handler(psmouse, NULL);
+ rc = psmouse->protocol_handler(psmouse);
if (rc != PSMOUSE_GOOD_DATA)
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;
+ failed = true;
}
if (failed) {
static void psmouse_cleanup(struct serio *serio)
{
struct psmouse *psmouse = serio_get_drvdata(serio);
+ struct psmouse *parent = NULL;
+
+ mutex_lock(&psmouse_mutex);
+
+ if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
+ parent = serio_get_drvdata(serio->parent);
+ psmouse_deactivate(parent);
+ }
+
+ psmouse_deactivate(psmouse);
+
+ if (psmouse->cleanup)
+ psmouse->cleanup(psmouse);
psmouse_reset(psmouse);
+
+/*
+ * Some boxes, such as HP nx7400, get terribly confused if mouse
+ * is not fully enabled before suspending/shutting down.
+ */
+ ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE);
+
+ if (parent) {
+ if (parent->pt_deactivate)
+ parent->pt_deactivate(parent);
+
+ psmouse_activate(parent);
+ }
+
+ mutex_unlock(&psmouse_mutex);
}
/*
{
struct input_dev *input_dev = psmouse->dev;
- input_dev->private = psmouse;
- input_dev->cdev.dev = &psmouse->ps2dev.serio->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);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+ input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
+ BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
+ input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
psmouse->set_rate = psmouse_set_rate;
psmouse->set_resolution = psmouse_set_resolution;
psmouse->type = proto->type;
}
else
- psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1);
+ psmouse->type = psmouse_extensions(psmouse,
+ psmouse_max_proto, true);
/*
* If mouse's packet size is 3 there is no point in polling the
{
struct psmouse *psmouse, *parent = NULL;
struct input_dev *input_dev;
- int retval = -ENOMEM;
+ int retval = 0, error = -ENOMEM;
mutex_lock(&psmouse_mutex);
psmouse = kzalloc(sizeof(struct psmouse), GFP_KERNEL);
input_dev = input_allocate_device();
if (!psmouse || !input_dev)
- goto out;
+ goto err_free;
ps2_init(&psmouse->ps2dev, serio);
- INIT_WORK(&psmouse->resync_work, psmouse_resync, psmouse);
+ INIT_DELAYED_WORK(&psmouse->resync_work, psmouse_resync);
psmouse->dev = input_dev;
snprintf(psmouse->phys, sizeof(psmouse->phys), "%s/input0", serio->phys);
serio_set_drvdata(serio, psmouse);
- retval = serio_open(serio, drv);
- if (retval)
- goto out;
+ error = serio_open(serio, drv);
+ if (error)
+ goto err_clear_drvdata;
if (psmouse_probe(psmouse) < 0) {
- serio_close(serio);
- retval = -ENODEV;
- goto out;
+ error = -ENODEV;
+ goto err_close_serio;
}
psmouse->rate = psmouse_rate;
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
psmouse_initialize(psmouse);
- input_register_device(psmouse->dev);
+ error = input_register_device(psmouse->dev);
+ if (error)
+ goto err_protocol_disconnect;
if (parent && parent->pt_activate)
parent->pt_activate(parent);
- sysfs_create_group(&serio->dev.kobj, &psmouse_attribute_group);
+ error = sysfs_create_group(&serio->dev.kobj, &psmouse_attribute_group);
+ if (error)
+ goto err_pt_deactivate;
psmouse_activate(psmouse);
- retval = 0;
-
-out:
- if (retval) {
- serio_set_drvdata(serio, NULL);
- input_free_device(input_dev);
- kfree(psmouse);
- }
-
+ out:
/* If this is a pass-through port the parent needs to be re-activated */
if (parent)
psmouse_activate(parent);
mutex_unlock(&psmouse_mutex);
return retval;
+
+ 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);
+ psmouse_set_state(psmouse, PSMOUSE_IGNORE);
+ err_close_serio:
+ serio_close(serio);
+ err_clear_drvdata:
+ serio_set_drvdata(serio, NULL);
+ err_free:
+ input_free_device(input_dev);
+ kfree(psmouse);
+
+ retval = error;
+ goto out;
}
if (psmouse->reconnect(psmouse))
goto out;
} else if (psmouse_probe(psmouse) < 0 ||
- psmouse->type != psmouse_extensions(psmouse, psmouse_max_proto, 0))
+ psmouse->type != psmouse_extensions(psmouse,
+ psmouse_max_proto, false)) {
goto out;
+ }
/* ok, the device type (and capabilities) match the old one,
* we can continue using it, complete intialization
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);
static ssize_t psmouse_show_int_attr(struct psmouse *psmouse, void *offset, char *buf)
{
- unsigned long *field = (unsigned long *)((char *)psmouse + (size_t)offset);
+ unsigned int *field = (unsigned int *)((char *)psmouse + (size_t)offset);
- return sprintf(buf, "%lu\n", *field);
+ return sprintf(buf, "%u\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 int *field = (unsigned int *)((char *)psmouse + (size_t)offset);
unsigned long value;
- char *rest;
- value = simple_strtoul(buf, &rest, 10);
- if (*rest)
+ if (strict_strtoul(buf, 10, &value))
+ return -EINVAL;
+
+ if ((unsigned int)value != value)
return -EINVAL;
*field = value;
{
struct serio *serio = psmouse->ps2dev.serio;
struct psmouse *parent = NULL;
- struct input_dev *new_dev;
- const struct psmouse_protocol *proto;
+ struct input_dev *old_dev, *new_dev;
+ const struct psmouse_protocol *proto, *old_proto;
+ int error;
int retry = 0;
- if (!(proto = psmouse_protocol_by_name(buf, count)))
+ proto = psmouse_protocol_by_name(buf, count);
+ if (!proto)
return -EINVAL;
if (psmouse->type == proto->type)
return count;
- if (!(new_dev = input_allocate_device()))
+ new_dev = input_allocate_device();
+ if (!new_dev)
return -ENOMEM;
while (serio->child) {
if (++retry > 3) {
- printk(KERN_WARNING "psmouse: failed to destroy child port, protocol change aborted.\n");
+ printk(KERN_WARNING
+ "psmouse: failed to destroy child port, "
+ "protocol change aborted.\n");
input_free_device(new_dev);
return -EIO;
}
parent->pt_deactivate(parent);
}
+ old_dev = psmouse->dev;
+ old_proto = psmouse_protocol_by_type(psmouse->type);
+
if (psmouse->disconnect)
psmouse->disconnect(psmouse);
psmouse_set_state(psmouse, PSMOUSE_IGNORE);
- input_unregister_device(psmouse->dev);
psmouse->dev = new_dev;
psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
psmouse_initialize(psmouse);
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
- input_register_device(psmouse->dev);
+ error = input_register_device(psmouse->dev);
+ if (error) {
+ if (psmouse->disconnect)
+ psmouse->disconnect(psmouse);
+
+ psmouse_set_state(psmouse, PSMOUSE_IGNORE);
+ input_free_device(new_dev);
+ psmouse->dev = old_dev;
+ psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
+ psmouse_switch_protocol(psmouse, old_proto);
+ psmouse_initialize(psmouse);
+ psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
+
+ return error;
+ }
+
+ input_unregister_device(old_dev);
if (parent && parent->pt_activate)
parent->pt_activate(parent);
static ssize_t psmouse_attr_set_rate(struct psmouse *psmouse, void *data, const char *buf, size_t count)
{
unsigned long value;
- char *rest;
- value = simple_strtoul(buf, &rest, 10);
- if (*rest)
+ if (strict_strtoul(buf, 10, &value))
return -EINVAL;
psmouse->set_rate(psmouse, value);
static ssize_t psmouse_attr_set_resolution(struct psmouse *psmouse, void *data, const char *buf, size_t count)
{
unsigned long value;
- char *rest;
- value = simple_strtoul(buf, &rest, 10);
- if (*rest)
+ if (strict_strtoul(buf, 10, &value))
return -EINVAL;
psmouse->set_resolution(psmouse, value);
{
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;
+
kpsmoused_wq = create_singlethread_workqueue("kpsmoused");
if (!kpsmoused_wq) {
printk(KERN_ERR "psmouse: failed to create kpsmoused workqueue\n");
return -ENOMEM;
}
- serio_register_driver(&psmouse_drv);
+ err = serio_register_driver(&psmouse_drv);
+ if (err)
+ destroy_workqueue(kpsmoused_wq);
- return 0;
+ return err;
}
static void __exit psmouse_exit(void)