Input: psmouse - introduce notion of SMBus companions
Prepare PS/2 mouse drivers to work with devices that are accessible both via PS/2 and SMBus, which provides higher bandwidth, and thus suits better for modern multi-touch devices. We expect that SMBus drivers will take control over the device, so when we detect SMBus "protocol" we forego registering input device, or enabling PS/2 device reports (as it usually makes device unresponsive to access over SMBus). Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
This commit is contained in:
parent
085fa80dfd
commit
c774326a21
|
@ -1424,9 +1424,8 @@ static void psmouse_cleanup(struct serio *serio)
|
||||||
*/
|
*/
|
||||||
static void psmouse_disconnect(struct serio *serio)
|
static void psmouse_disconnect(struct serio *serio)
|
||||||
{
|
{
|
||||||
struct psmouse *psmouse, *parent = NULL;
|
struct psmouse *psmouse = serio_get_drvdata(serio);
|
||||||
|
struct psmouse *parent = NULL;
|
||||||
psmouse = serio_get_drvdata(serio);
|
|
||||||
|
|
||||||
sysfs_remove_group(&serio->dev.kobj, &psmouse_attribute_group);
|
sysfs_remove_group(&serio->dev.kobj, &psmouse_attribute_group);
|
||||||
|
|
||||||
|
@ -1454,7 +1453,10 @@ static void psmouse_disconnect(struct serio *serio)
|
||||||
|
|
||||||
serio_close(serio);
|
serio_close(serio);
|
||||||
serio_set_drvdata(serio, NULL);
|
serio_set_drvdata(serio, NULL);
|
||||||
|
|
||||||
|
if (psmouse->dev)
|
||||||
input_unregister_device(psmouse->dev);
|
input_unregister_device(psmouse->dev);
|
||||||
|
|
||||||
kfree(psmouse);
|
kfree(psmouse);
|
||||||
|
|
||||||
if (parent)
|
if (parent)
|
||||||
|
@ -1575,12 +1577,18 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
|
||||||
|
|
||||||
psmouse_switch_protocol(psmouse, NULL);
|
psmouse_switch_protocol(psmouse, NULL);
|
||||||
|
|
||||||
|
if (!psmouse->protocol->smbus_companion) {
|
||||||
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
|
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
|
||||||
psmouse_initialize(psmouse);
|
psmouse_initialize(psmouse);
|
||||||
|
|
||||||
error = input_register_device(psmouse->dev);
|
error = input_register_device(input_dev);
|
||||||
if (error)
|
if (error)
|
||||||
goto err_protocol_disconnect;
|
goto err_protocol_disconnect;
|
||||||
|
} else {
|
||||||
|
/* Smbus companion will be reporting events, not us. */
|
||||||
|
input_free_device(input_dev);
|
||||||
|
psmouse->dev = input_dev = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (parent && parent->pt_activate)
|
if (parent && parent->pt_activate)
|
||||||
parent->pt_activate(parent);
|
parent->pt_activate(parent);
|
||||||
|
@ -1589,6 +1597,11 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
|
||||||
if (error)
|
if (error)
|
||||||
goto err_pt_deactivate;
|
goto err_pt_deactivate;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PS/2 devices having SMBus companions should stay disabled
|
||||||
|
* on PS/2 side, in order to have SMBus part operable.
|
||||||
|
*/
|
||||||
|
if (!psmouse->protocol->smbus_companion)
|
||||||
psmouse_activate(psmouse);
|
psmouse_activate(psmouse);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
@ -1602,8 +1615,10 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
|
||||||
err_pt_deactivate:
|
err_pt_deactivate:
|
||||||
if (parent && parent->pt_deactivate)
|
if (parent && parent->pt_deactivate)
|
||||||
parent->pt_deactivate(parent);
|
parent->pt_deactivate(parent);
|
||||||
input_unregister_device(psmouse->dev);
|
if (input_dev) {
|
||||||
|
input_unregister_device(input_dev);
|
||||||
input_dev = NULL; /* so we don't try to free it below */
|
input_dev = NULL; /* so we don't try to free it below */
|
||||||
|
}
|
||||||
err_protocol_disconnect:
|
err_protocol_disconnect:
|
||||||
if (psmouse->disconnect)
|
if (psmouse->disconnect)
|
||||||
psmouse->disconnect(psmouse);
|
psmouse->disconnect(psmouse);
|
||||||
|
@ -1665,14 +1680,21 @@ static int __psmouse_reconnect(struct serio *serio, bool fast_reconnect)
|
||||||
* OK, the device type (and capabilities) match the old one,
|
* OK, the device type (and capabilities) match the old one,
|
||||||
* we can continue using it, complete initialization
|
* we can continue using it, complete initialization
|
||||||
*/
|
*/
|
||||||
|
if (!psmouse->protocol->smbus_companion) {
|
||||||
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
|
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
|
||||||
|
|
||||||
psmouse_initialize(psmouse);
|
psmouse_initialize(psmouse);
|
||||||
|
}
|
||||||
|
|
||||||
if (parent && parent->pt_activate)
|
if (parent && parent->pt_activate)
|
||||||
parent->pt_activate(parent);
|
parent->pt_activate(parent);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PS/2 devices having SMBus companions should stay disabled
|
||||||
|
* on PS/2 side, in order to have SMBus part operable.
|
||||||
|
*/
|
||||||
|
if (!psmouse->protocol->smbus_companion)
|
||||||
psmouse_activate(psmouse);
|
psmouse_activate(psmouse);
|
||||||
|
|
||||||
rc = 0;
|
rc = 0;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
@ -1732,9 +1754,11 @@ ssize_t psmouse_attr_show_helper(struct device *dev, struct device_attribute *de
|
||||||
{
|
{
|
||||||
struct serio *serio = to_serio_port(dev);
|
struct serio *serio = to_serio_port(dev);
|
||||||
struct psmouse_attribute *attr = to_psmouse_attr(devattr);
|
struct psmouse_attribute *attr = to_psmouse_attr(devattr);
|
||||||
struct psmouse *psmouse;
|
struct psmouse *psmouse = serio_get_drvdata(serio);
|
||||||
|
|
||||||
psmouse = serio_get_drvdata(serio);
|
if (psmouse->protocol->smbus_companion &&
|
||||||
|
devattr != &psmouse_attr_protocol.dattr)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
return attr->show(psmouse, attr->data, buf);
|
return attr->show(psmouse, attr->data, buf);
|
||||||
}
|
}
|
||||||
|
@ -1753,6 +1777,12 @@ ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *dev
|
||||||
|
|
||||||
psmouse = serio_get_drvdata(serio);
|
psmouse = serio_get_drvdata(serio);
|
||||||
|
|
||||||
|
if (psmouse->protocol->smbus_companion &&
|
||||||
|
devattr != &psmouse_attr_protocol.dattr) {
|
||||||
|
retval = -ENOENT;
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
if (attr->protect) {
|
if (attr->protect) {
|
||||||
if (psmouse->state == PSMOUSE_IGNORE) {
|
if (psmouse->state == PSMOUSE_IGNORE) {
|
||||||
retval = -ENODEV;
|
retval = -ENODEV;
|
||||||
|
@ -1764,13 +1794,14 @@ ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *dev
|
||||||
psmouse_deactivate(parent);
|
psmouse_deactivate(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!psmouse->protocol->smbus_companion)
|
||||||
psmouse_deactivate(psmouse);
|
psmouse_deactivate(psmouse);
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = attr->set(psmouse, attr->data, buf, count);
|
retval = attr->set(psmouse, attr->data, buf, count);
|
||||||
|
|
||||||
if (attr->protect) {
|
if (attr->protect) {
|
||||||
if (retval != -ENODEV)
|
if (retval != -ENODEV && !psmouse->protocol->smbus_companion)
|
||||||
psmouse_activate(psmouse);
|
psmouse_activate(psmouse);
|
||||||
|
|
||||||
if (parent)
|
if (parent)
|
||||||
|
@ -1879,6 +1910,10 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co
|
||||||
psmouse_initialize(psmouse);
|
psmouse_initialize(psmouse);
|
||||||
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
|
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
|
||||||
|
|
||||||
|
if (psmouse->protocol->smbus_companion) {
|
||||||
|
input_free_device(psmouse->dev);
|
||||||
|
psmouse->dev = NULL;
|
||||||
|
} else {
|
||||||
error = input_register_device(psmouse->dev);
|
error = input_register_device(psmouse->dev);
|
||||||
if (error) {
|
if (error) {
|
||||||
if (psmouse->disconnect)
|
if (psmouse->disconnect)
|
||||||
|
@ -1894,7 +1929,9 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (old_dev)
|
||||||
input_unregister_device(old_dev);
|
input_unregister_device(old_dev);
|
||||||
|
|
||||||
if (parent && parent->pt_activate)
|
if (parent && parent->pt_activate)
|
||||||
|
|
|
@ -76,6 +76,7 @@ struct psmouse_protocol {
|
||||||
bool maxproto;
|
bool maxproto;
|
||||||
bool ignore_parity; /* Protocol should ignore parity errors from KBC */
|
bool ignore_parity; /* Protocol should ignore parity errors from KBC */
|
||||||
bool try_passthru; /* Try protocol also on passthrough ports */
|
bool try_passthru; /* Try protocol also on passthrough ports */
|
||||||
|
bool smbus_companion; /* "Protocol" is a stub, device is on SMBus */
|
||||||
const char *name;
|
const char *name;
|
||||||
const char *alias;
|
const char *alias;
|
||||||
int (*detect)(struct psmouse *, bool);
|
int (*detect)(struct psmouse *, bool);
|
||||||
|
|
Loading…
Reference in New Issue