diff options
Diffstat (limited to 'drivers/input/mouse/psmouse-base.c')
-rw-r--r-- | drivers/input/mouse/psmouse-base.c | 84 |
1 files changed, 59 insertions, 25 deletions
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 6f9b2c7cc9c2..9144df65e703 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c | |||
@@ -1102,7 +1102,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) | |||
1102 | { | 1102 | { |
1103 | struct psmouse *psmouse, *parent = NULL; | 1103 | struct psmouse *psmouse, *parent = NULL; |
1104 | struct input_dev *input_dev; | 1104 | struct input_dev *input_dev; |
1105 | int retval = -ENOMEM; | 1105 | int retval = 0, error = -ENOMEM; |
1106 | 1106 | ||
1107 | mutex_lock(&psmouse_mutex); | 1107 | mutex_lock(&psmouse_mutex); |
1108 | 1108 | ||
@@ -1118,7 +1118,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) | |||
1118 | psmouse = kzalloc(sizeof(struct psmouse), GFP_KERNEL); | 1118 | psmouse = kzalloc(sizeof(struct psmouse), GFP_KERNEL); |
1119 | input_dev = input_allocate_device(); | 1119 | input_dev = input_allocate_device(); |
1120 | if (!psmouse || !input_dev) | 1120 | if (!psmouse || !input_dev) |
1121 | goto out; | 1121 | goto err_free; |
1122 | 1122 | ||
1123 | ps2_init(&psmouse->ps2dev, serio); | 1123 | ps2_init(&psmouse->ps2dev, serio); |
1124 | INIT_WORK(&psmouse->resync_work, psmouse_resync, psmouse); | 1124 | INIT_WORK(&psmouse->resync_work, psmouse_resync, psmouse); |
@@ -1129,14 +1129,13 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) | |||
1129 | 1129 | ||
1130 | serio_set_drvdata(serio, psmouse); | 1130 | serio_set_drvdata(serio, psmouse); |
1131 | 1131 | ||
1132 | retval = serio_open(serio, drv); | 1132 | error = serio_open(serio, drv); |
1133 | if (retval) | 1133 | if (error) |
1134 | goto out; | 1134 | goto err_clear_drvdata; |
1135 | 1135 | ||
1136 | if (psmouse_probe(psmouse) < 0) { | 1136 | if (psmouse_probe(psmouse) < 0) { |
1137 | serio_close(serio); | 1137 | error = -ENODEV; |
1138 | retval = -ENODEV; | 1138 | goto err_close_serio; |
1139 | goto out; | ||
1140 | } | 1139 | } |
1141 | 1140 | ||
1142 | psmouse->rate = psmouse_rate; | 1141 | psmouse->rate = psmouse_rate; |
@@ -1150,30 +1149,44 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) | |||
1150 | psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); | 1149 | psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); |
1151 | psmouse_initialize(psmouse); | 1150 | psmouse_initialize(psmouse); |
1152 | 1151 | ||
1153 | input_register_device(psmouse->dev); | 1152 | error = input_register_device(psmouse->dev); |
1153 | if (error) | ||
1154 | goto err_protocol_disconnect; | ||
1154 | 1155 | ||
1155 | if (parent && parent->pt_activate) | 1156 | if (parent && parent->pt_activate) |
1156 | parent->pt_activate(parent); | 1157 | parent->pt_activate(parent); |
1157 | 1158 | ||
1158 | sysfs_create_group(&serio->dev.kobj, &psmouse_attribute_group); | 1159 | error = sysfs_create_group(&serio->dev.kobj, &psmouse_attribute_group); |
1160 | if (error) | ||
1161 | goto err_pt_deactivate; | ||
1159 | 1162 | ||
1160 | psmouse_activate(psmouse); | 1163 | psmouse_activate(psmouse); |
1161 | 1164 | ||
1162 | retval = 0; | 1165 | out: |
1163 | |||
1164 | out: | ||
1165 | if (retval) { | ||
1166 | serio_set_drvdata(serio, NULL); | ||
1167 | input_free_device(input_dev); | ||
1168 | kfree(psmouse); | ||
1169 | } | ||
1170 | |||
1171 | /* If this is a pass-through port the parent needs to be re-activated */ | 1166 | /* If this is a pass-through port the parent needs to be re-activated */ |
1172 | if (parent) | 1167 | if (parent) |
1173 | psmouse_activate(parent); | 1168 | psmouse_activate(parent); |
1174 | 1169 | ||
1175 | mutex_unlock(&psmouse_mutex); | 1170 | mutex_unlock(&psmouse_mutex); |
1176 | return retval; | 1171 | return retval; |
1172 | |||
1173 | err_pt_deactivate: | ||
1174 | if (parent && parent->pt_deactivate) | ||
1175 | parent->pt_deactivate(parent); | ||
1176 | err_protocol_disconnect: | ||
1177 | if (psmouse->disconnect) | ||
1178 | psmouse->disconnect(psmouse); | ||
1179 | psmouse_set_state(psmouse, PSMOUSE_IGNORE); | ||
1180 | err_close_serio: | ||
1181 | serio_close(serio); | ||
1182 | err_clear_drvdata: | ||
1183 | serio_set_drvdata(serio, NULL); | ||
1184 | err_free: | ||
1185 | input_free_device(input_dev); | ||
1186 | kfree(psmouse); | ||
1187 | |||
1188 | retval = error; | ||
1189 | goto out; | ||
1177 | } | 1190 | } |
1178 | 1191 | ||
1179 | 1192 | ||
@@ -1365,17 +1378,20 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co | |||
1365 | { | 1378 | { |
1366 | struct serio *serio = psmouse->ps2dev.serio; | 1379 | struct serio *serio = psmouse->ps2dev.serio; |
1367 | struct psmouse *parent = NULL; | 1380 | struct psmouse *parent = NULL; |
1368 | struct input_dev *new_dev; | 1381 | struct input_dev *old_dev, *new_dev; |
1369 | const struct psmouse_protocol *proto; | 1382 | const struct psmouse_protocol *proto, *old_proto; |
1383 | int error; | ||
1370 | int retry = 0; | 1384 | int retry = 0; |
1371 | 1385 | ||
1372 | if (!(proto = psmouse_protocol_by_name(buf, count))) | 1386 | proto = psmouse_protocol_by_name(buf, count); |
1387 | if (!proto) | ||
1373 | return -EINVAL; | 1388 | return -EINVAL; |
1374 | 1389 | ||
1375 | if (psmouse->type == proto->type) | 1390 | if (psmouse->type == proto->type) |
1376 | return count; | 1391 | return count; |
1377 | 1392 | ||
1378 | if (!(new_dev = input_allocate_device())) | 1393 | new_dev = input_allocate_device(); |
1394 | if (!new_dev) | ||
1379 | return -ENOMEM; | 1395 | return -ENOMEM; |
1380 | 1396 | ||
1381 | while (serio->child) { | 1397 | while (serio->child) { |
@@ -1408,11 +1424,13 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co | |||
1408 | parent->pt_deactivate(parent); | 1424 | parent->pt_deactivate(parent); |
1409 | } | 1425 | } |
1410 | 1426 | ||
1427 | old_dev = psmouse->dev; | ||
1428 | old_proto = psmouse_protocol_by_type(psmouse->type); | ||
1429 | |||
1411 | if (psmouse->disconnect) | 1430 | if (psmouse->disconnect) |
1412 | psmouse->disconnect(psmouse); | 1431 | psmouse->disconnect(psmouse); |
1413 | 1432 | ||
1414 | psmouse_set_state(psmouse, PSMOUSE_IGNORE); | 1433 | psmouse_set_state(psmouse, PSMOUSE_IGNORE); |
1415 | input_unregister_device(psmouse->dev); | ||
1416 | 1434 | ||
1417 | psmouse->dev = new_dev; | 1435 | psmouse->dev = new_dev; |
1418 | psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); | 1436 | psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); |
@@ -1426,7 +1444,23 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co | |||
1426 | psmouse_initialize(psmouse); | 1444 | psmouse_initialize(psmouse); |
1427 | psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); | 1445 | psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); |
1428 | 1446 | ||
1429 | input_register_device(psmouse->dev); | 1447 | error = input_register_device(psmouse->dev); |
1448 | if (error) { | ||
1449 | if (psmouse->disconnect) | ||
1450 | psmouse->disconnect(psmouse); | ||
1451 | |||
1452 | psmouse_set_state(psmouse, PSMOUSE_IGNORE); | ||
1453 | input_free_device(new_dev); | ||
1454 | psmouse->dev = old_dev; | ||
1455 | psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); | ||
1456 | psmouse_switch_protocol(psmouse, old_proto); | ||
1457 | psmouse_initialize(psmouse); | ||
1458 | psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); | ||
1459 | |||
1460 | return error; | ||
1461 | } | ||
1462 | |||
1463 | input_unregister_device(old_dev); | ||
1430 | 1464 | ||
1431 | if (parent && parent->pt_activate) | 1465 | if (parent && parent->pt_activate) |
1432 | parent->pt_activate(parent); | 1466 | parent->pt_activate(parent); |