Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 3549
b: refs/heads/master
c: 04df192
h: refs/heads/master
i:
  3547: 75298b2
v: v3
  • Loading branch information
Dmitry Torokhov committed Jun 1, 2005
1 parent b55d656 commit e863490
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 19 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 8121152c1770ef1cd029030d51802c65c489950d
refs/heads/master: 04df1925fcda9a35c716423ad2b73abd70eb0913
54 changes: 44 additions & 10 deletions trunk/drivers/input/mouse/psmouse-base.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ __obsolete_setup("psmouse_smartscroll=");
__obsolete_setup("psmouse_resetafter=");
__obsolete_setup("psmouse_rate=");

/*
* psmouse_sem protects all operations changing state of mouse
* (connecting, disconnecting, changing rate or resolution via
* sysfs). We could use a per-device semaphore but since there
* rarely more than one PS/2 mouse connected and since semaphore
* is taken in "slow" paths it is not worth it.
*/
static DECLARE_MUTEX(psmouse_sem);

static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "ThinkPS/2", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2", "AlpsPS/2", "LBPS/2" };

/*
Expand Down Expand Up @@ -667,30 +676,40 @@ static void psmouse_cleanup(struct serio *serio)

static void psmouse_disconnect(struct serio *serio)
{
struct psmouse *psmouse, *parent;
struct psmouse *psmouse, *parent = NULL;

psmouse = serio_get_drvdata(serio);

device_remove_file(&serio->dev, &psmouse_attr_rate);
device_remove_file(&serio->dev, &psmouse_attr_resolution);
device_remove_file(&serio->dev, &psmouse_attr_resetafter);

psmouse = serio_get_drvdata(serio);
down(&psmouse_sem);

psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);

if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
parent = serio_get_drvdata(serio->parent);
if (parent->pt_deactivate)
parent->pt_deactivate(parent);
psmouse_deactivate(parent);
}

if (psmouse->disconnect)
psmouse->disconnect(psmouse);

if (parent && parent->pt_deactivate)
parent->pt_deactivate(parent);

psmouse_set_state(psmouse, PSMOUSE_IGNORE);

input_unregister_device(&psmouse->dev);
serio_close(serio);
serio_set_drvdata(serio, NULL);
kfree(psmouse);

if (parent)
psmouse_activate(parent);

up(&psmouse_sem);
}

/*
Expand All @@ -702,6 +721,8 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
struct psmouse *psmouse, *parent = NULL;
int retval;

down(&psmouse_sem);

/*
* If this is a pass-through port deactivate parent so the device
* connected to this port can be successfully identified
Expand All @@ -711,13 +732,11 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
psmouse_deactivate(parent);
}

if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL))) {
if (!(psmouse = kcalloc(1, sizeof(struct psmouse), GFP_KERNEL))) {
retval = -ENOMEM;
goto out;
}

memset(psmouse, 0, sizeof(struct psmouse));

ps2_init(&psmouse->ps2dev, serio);
sprintf(psmouse->phys, "%s/input0", serio->phys);
psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
Expand Down Expand Up @@ -785,10 +804,11 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
retval = 0;

out:
/* If this is a pass-through port the parent awaits to be activated */
/* If this is a pass-through port the parent needs to be re-activated */
if (parent)
psmouse_activate(parent);

up(&psmouse_sem);
return retval;
}

Expand All @@ -805,6 +825,8 @@ static int psmouse_reconnect(struct serio *serio)
return -1;
}

down(&psmouse_sem);

if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
parent = serio_get_drvdata(serio->parent);
psmouse_deactivate(parent);
Expand Down Expand Up @@ -837,6 +859,7 @@ static int psmouse_reconnect(struct serio *serio)
if (parent)
psmouse_activate(parent);

up(&psmouse_sem);
return rc;
}

Expand Down Expand Up @@ -907,7 +930,16 @@ ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t coun

if (serio->drv != &psmouse_drv) {
retval = -ENODEV;
goto out;
goto out_unpin;
}

retval = down_interruptible(&psmouse_sem);
if (retval)
goto out_unpin;

if (psmouse->state == PSMOUSE_IGNORE) {
retval = -ENODEV;
goto out_up;
}

if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
Expand All @@ -922,7 +954,9 @@ ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t coun
if (parent)
psmouse_activate(parent);

out:
out_up:
up(&psmouse_sem);
out_unpin:
serio_unpin_driver(serio);
return retval;
}
Expand Down
44 changes: 36 additions & 8 deletions trunk/drivers/input/serio/serio.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,37 @@ static void serio_destroy_port(struct serio *serio);
static void serio_reconnect_port(struct serio *serio);
static void serio_disconnect_port(struct serio *serio);

static int serio_connect_driver(struct serio *serio, struct serio_driver *drv)
{
int retval;

down(&serio->drv_sem);
retval = drv->connect(serio, drv);
up(&serio->drv_sem);

return retval;
}

static int serio_reconnect_driver(struct serio *serio)
{
int retval = -1;

down(&serio->drv_sem);
if (serio->drv && serio->drv->reconnect)
retval = serio->drv->reconnect(serio);
up(&serio->drv_sem);

return retval;
}

static void serio_disconnect_driver(struct serio *serio)
{
down(&serio->drv_sem);
if (serio->drv)
serio->drv->disconnect(serio);
up(&serio->drv_sem);
}

static int serio_match_port(const struct serio_device_id *ids, struct serio *serio)
{
while (ids->type || ids->proto) {
Expand All @@ -90,7 +121,7 @@ static void serio_bind_driver(struct serio *serio, struct serio_driver *drv)

if (serio_match_port(drv->id_table, serio)) {
serio->dev.driver = &drv->driver;
if (drv->connect(serio, drv)) {
if (serio_connect_driver(serio, drv)) {
serio->dev.driver = NULL;
goto out;
}
Expand Down Expand Up @@ -550,7 +581,7 @@ static void serio_destroy_port(struct serio *serio)
static void serio_reconnect_port(struct serio *serio)
{
do {
if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) {
if (serio_reconnect_driver(serio)) {
serio_disconnect_port(serio);
serio_find_driver(serio);
/* Ok, old children are now gone, we are done */
Expand Down Expand Up @@ -679,15 +710,14 @@ static int serio_driver_probe(struct device *dev)
struct serio *serio = to_serio_port(dev);
struct serio_driver *drv = to_serio_driver(dev->driver);

return drv->connect(serio, drv);
return serio_connect_driver(serio, drv);
}

static int serio_driver_remove(struct device *dev)
{
struct serio *serio = to_serio_port(dev);
struct serio_driver *drv = to_serio_driver(dev->driver);

drv->disconnect(serio);
serio_disconnect_driver(serio);
return 0;
}

Expand Down Expand Up @@ -723,11 +753,9 @@ void serio_unregister_driver(struct serio_driver *drv)

static void serio_set_drv(struct serio *serio, struct serio_driver *drv)
{
down(&serio->drv_sem);
serio_pause_rx(serio);
serio->drv = drv;
serio_continue_rx(serio);
up(&serio->drv_sem);
}

static int serio_bus_match(struct device *dev, struct device_driver *drv)
Expand Down Expand Up @@ -787,7 +815,7 @@ static int serio_resume(struct device *dev)
{
struct serio *serio = to_serio_port(dev);

if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) {
if (serio_reconnect_driver(serio)) {
/*
* Driver re-probing can take a while, so better let kseriod
* deal with it.
Expand Down

0 comments on commit e863490

Please sign in to comment.