diff options
author | Dmitry Torokhov <dtor@insightbb.com> | 2006-11-05 22:39:56 -0500 |
---|---|---|
committer | Dmitry Torokhov <dtor@insightbb.com> | 2006-11-05 22:39:56 -0500 |
commit | 2b03b60e6b8635fffdd15d5d24943950f2bbf96e (patch) | |
tree | 17f0354b7edb08920a89e663ef724c84518c49fa /drivers/input/keyboard/atkbd.c | |
parent | 41ad5fbabda0c3930136bb40cfc7a0c23013365f (diff) |
Input: keyboards - handle errors when registering input devices
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/keyboard/atkbd.c')
-rw-r--r-- | drivers/input/keyboard/atkbd.c | 159 |
1 files changed, 129 insertions, 30 deletions
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index cbb93669d1c..73c6946b2d9 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c | |||
@@ -939,7 +939,7 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv) | |||
939 | atkbd = kzalloc(sizeof(struct atkbd), GFP_KERNEL); | 939 | atkbd = kzalloc(sizeof(struct atkbd), GFP_KERNEL); |
940 | dev = input_allocate_device(); | 940 | dev = input_allocate_device(); |
941 | if (!atkbd || !dev) | 941 | if (!atkbd || !dev) |
942 | goto fail; | 942 | goto fail1; |
943 | 943 | ||
944 | atkbd->dev = dev; | 944 | atkbd->dev = dev; |
945 | ps2_init(&atkbd->ps2dev, serio); | 945 | ps2_init(&atkbd->ps2dev, serio); |
@@ -967,14 +967,13 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv) | |||
967 | 967 | ||
968 | err = serio_open(serio, drv); | 968 | err = serio_open(serio, drv); |
969 | if (err) | 969 | if (err) |
970 | goto fail; | 970 | goto fail2; |
971 | 971 | ||
972 | if (atkbd->write) { | 972 | if (atkbd->write) { |
973 | 973 | ||
974 | if (atkbd_probe(atkbd)) { | 974 | if (atkbd_probe(atkbd)) { |
975 | serio_close(serio); | ||
976 | err = -ENODEV; | 975 | err = -ENODEV; |
977 | goto fail; | 976 | goto fail3; |
978 | } | 977 | } |
979 | 978 | ||
980 | atkbd->set = atkbd_select_set(atkbd, atkbd_set, atkbd_extra); | 979 | atkbd->set = atkbd_select_set(atkbd, atkbd_set, atkbd_extra); |
@@ -988,16 +987,22 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv) | |||
988 | atkbd_set_keycode_table(atkbd); | 987 | atkbd_set_keycode_table(atkbd); |
989 | atkbd_set_device_attrs(atkbd); | 988 | atkbd_set_device_attrs(atkbd); |
990 | 989 | ||
991 | sysfs_create_group(&serio->dev.kobj, &atkbd_attribute_group); | 990 | err = sysfs_create_group(&serio->dev.kobj, &atkbd_attribute_group); |
991 | if (err) | ||
992 | goto fail3; | ||
992 | 993 | ||
993 | atkbd_enable(atkbd); | 994 | atkbd_enable(atkbd); |
994 | 995 | ||
995 | input_register_device(atkbd->dev); | 996 | err = input_register_device(atkbd->dev); |
997 | if (err) | ||
998 | goto fail4; | ||
996 | 999 | ||
997 | return 0; | 1000 | return 0; |
998 | 1001 | ||
999 | fail: serio_set_drvdata(serio, NULL); | 1002 | fail4: sysfs_remove_group(&serio->dev.kobj, &atkbd_attribute_group); |
1000 | input_free_device(dev); | 1003 | fail3: serio_close(serio); |
1004 | fail2: serio_set_drvdata(serio, NULL); | ||
1005 | fail1: input_free_device(dev); | ||
1001 | kfree(atkbd); | 1006 | kfree(atkbd); |
1002 | return err; | 1007 | return err; |
1003 | } | 1008 | } |
@@ -1133,9 +1138,11 @@ static ssize_t atkbd_show_extra(struct atkbd *atkbd, char *buf) | |||
1133 | 1138 | ||
1134 | static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t count) | 1139 | static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t count) |
1135 | { | 1140 | { |
1136 | struct input_dev *new_dev; | 1141 | struct input_dev *old_dev, *new_dev; |
1137 | unsigned long value; | 1142 | unsigned long value; |
1138 | char *rest; | 1143 | char *rest; |
1144 | int err; | ||
1145 | unsigned char old_extra, old_set; | ||
1139 | 1146 | ||
1140 | if (!atkbd->write) | 1147 | if (!atkbd->write) |
1141 | return -EIO; | 1148 | return -EIO; |
@@ -1147,17 +1154,36 @@ static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t coun | |||
1147 | if (atkbd->extra != value) { | 1154 | if (atkbd->extra != value) { |
1148 | /* | 1155 | /* |
1149 | * Since device's properties will change we need to | 1156 | * Since device's properties will change we need to |
1150 | * unregister old device. But allocate new one first | 1157 | * unregister old device. But allocate and register |
1151 | * to make sure we have it. | 1158 | * new one first to make sure we have it. |
1152 | */ | 1159 | */ |
1153 | if (!(new_dev = input_allocate_device())) | 1160 | old_dev = atkbd->dev; |
1161 | old_extra = atkbd->extra; | ||
1162 | old_set = atkbd->set; | ||
1163 | |||
1164 | new_dev = input_allocate_device(); | ||
1165 | if (!new_dev) | ||
1154 | return -ENOMEM; | 1166 | return -ENOMEM; |
1155 | input_unregister_device(atkbd->dev); | 1167 | |
1156 | atkbd->dev = new_dev; | 1168 | atkbd->dev = new_dev; |
1157 | atkbd->set = atkbd_select_set(atkbd, atkbd->set, value); | 1169 | atkbd->set = atkbd_select_set(atkbd, atkbd->set, value); |
1158 | atkbd_activate(atkbd); | 1170 | atkbd_activate(atkbd); |
1171 | atkbd_set_keycode_table(atkbd); | ||
1159 | atkbd_set_device_attrs(atkbd); | 1172 | atkbd_set_device_attrs(atkbd); |
1160 | input_register_device(atkbd->dev); | 1173 | |
1174 | err = input_register_device(atkbd->dev); | ||
1175 | if (err) { | ||
1176 | input_free_device(new_dev); | ||
1177 | |||
1178 | atkbd->dev = old_dev; | ||
1179 | atkbd->set = atkbd_select_set(atkbd, old_set, old_extra); | ||
1180 | atkbd_set_keycode_table(atkbd); | ||
1181 | atkbd_set_device_attrs(atkbd); | ||
1182 | |||
1183 | return err; | ||
1184 | } | ||
1185 | input_unregister_device(old_dev); | ||
1186 | |||
1161 | } | 1187 | } |
1162 | return count; | 1188 | return count; |
1163 | } | 1189 | } |
@@ -1169,23 +1195,41 @@ static ssize_t atkbd_show_scroll(struct atkbd *atkbd, char *buf) | |||
1169 | 1195 | ||
1170 | static ssize_t atkbd_set_scroll(struct atkbd *atkbd, const char *buf, size_t count) | 1196 | static ssize_t atkbd_set_scroll(struct atkbd *atkbd, const char *buf, size_t count) |
1171 | { | 1197 | { |
1172 | struct input_dev *new_dev; | 1198 | struct input_dev *old_dev, *new_dev; |
1173 | unsigned long value; | 1199 | unsigned long value; |
1174 | char *rest; | 1200 | char *rest; |
1201 | int err; | ||
1202 | unsigned char old_scroll; | ||
1175 | 1203 | ||
1176 | value = simple_strtoul(buf, &rest, 10); | 1204 | value = simple_strtoul(buf, &rest, 10); |
1177 | if (*rest || value > 1) | 1205 | if (*rest || value > 1) |
1178 | return -EINVAL; | 1206 | return -EINVAL; |
1179 | 1207 | ||
1180 | if (atkbd->scroll != value) { | 1208 | if (atkbd->scroll != value) { |
1181 | if (!(new_dev = input_allocate_device())) | 1209 | old_dev = atkbd->dev; |
1210 | old_scroll = atkbd->scroll; | ||
1211 | |||
1212 | new_dev = input_allocate_device(); | ||
1213 | if (!new_dev) | ||
1182 | return -ENOMEM; | 1214 | return -ENOMEM; |
1183 | input_unregister_device(atkbd->dev); | 1215 | |
1184 | atkbd->dev = new_dev; | 1216 | atkbd->dev = new_dev; |
1185 | atkbd->scroll = value; | 1217 | atkbd->scroll = value; |
1186 | atkbd_set_keycode_table(atkbd); | 1218 | atkbd_set_keycode_table(atkbd); |
1187 | atkbd_set_device_attrs(atkbd); | 1219 | atkbd_set_device_attrs(atkbd); |
1188 | input_register_device(atkbd->dev); | 1220 | |
1221 | err = input_register_device(atkbd->dev); | ||
1222 | if (err) { | ||
1223 | input_free_device(new_dev); | ||
1224 | |||
1225 | atkbd->scroll = old_scroll; | ||
1226 | atkbd->dev = old_dev; | ||
1227 | atkbd_set_keycode_table(atkbd); | ||
1228 | atkbd_set_device_attrs(atkbd); | ||
1229 | |||
1230 | return err; | ||
1231 | } | ||
1232 | input_unregister_device(old_dev); | ||
1189 | } | 1233 | } |
1190 | return count; | 1234 | return count; |
1191 | } | 1235 | } |
@@ -1197,9 +1241,11 @@ static ssize_t atkbd_show_set(struct atkbd *atkbd, char *buf) | |||
1197 | 1241 | ||
1198 | static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count) | 1242 | static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count) |
1199 | { | 1243 | { |
1200 | struct input_dev *new_dev; | 1244 | struct input_dev *old_dev, *new_dev; |
1201 | unsigned long value; | 1245 | unsigned long value; |
1202 | char *rest; | 1246 | char *rest; |
1247 | int err; | ||
1248 | unsigned char old_set, old_extra; | ||
1203 | 1249 | ||
1204 | if (!atkbd->write) | 1250 | if (!atkbd->write) |
1205 | return -EIO; | 1251 | return -EIO; |
@@ -1209,15 +1255,32 @@ static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count) | |||
1209 | return -EINVAL; | 1255 | return -EINVAL; |
1210 | 1256 | ||
1211 | if (atkbd->set != value) { | 1257 | if (atkbd->set != value) { |
1212 | if (!(new_dev = input_allocate_device())) | 1258 | old_dev = atkbd->dev; |
1259 | old_extra = atkbd->extra; | ||
1260 | old_set = atkbd->set; | ||
1261 | |||
1262 | new_dev = input_allocate_device(); | ||
1263 | if (!new_dev) | ||
1213 | return -ENOMEM; | 1264 | return -ENOMEM; |
1214 | input_unregister_device(atkbd->dev); | 1265 | |
1215 | atkbd->dev = new_dev; | 1266 | atkbd->dev = new_dev; |
1216 | atkbd->set = atkbd_select_set(atkbd, value, atkbd->extra); | 1267 | atkbd->set = atkbd_select_set(atkbd, value, atkbd->extra); |
1217 | atkbd_activate(atkbd); | 1268 | atkbd_activate(atkbd); |
1218 | atkbd_set_keycode_table(atkbd); | 1269 | atkbd_set_keycode_table(atkbd); |
1219 | atkbd_set_device_attrs(atkbd); | 1270 | atkbd_set_device_attrs(atkbd); |
1220 | input_register_device(atkbd->dev); | 1271 | |
1272 | err = input_register_device(atkbd->dev); | ||
1273 | if (err) { | ||
1274 | input_free_device(new_dev); | ||
1275 | |||
1276 | atkbd->dev = old_dev; | ||
1277 | atkbd->set = atkbd_select_set(atkbd, old_set, old_extra); | ||
1278 | atkbd_set_keycode_table(atkbd); | ||
1279 | atkbd_set_device_attrs(atkbd); | ||
1280 | |||
1281 | return err; | ||
1282 | } | ||
1283 | input_unregister_device(old_dev); | ||
1221 | } | 1284 | } |
1222 | return count; | 1285 | return count; |
1223 | } | 1286 | } |
@@ -1229,9 +1292,11 @@ static ssize_t atkbd_show_softrepeat(struct atkbd *atkbd, char *buf) | |||
1229 | 1292 | ||
1230 | static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t count) | 1293 | static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t count) |
1231 | { | 1294 | { |
1232 | struct input_dev *new_dev; | 1295 | struct input_dev *old_dev, *new_dev; |
1233 | unsigned long value; | 1296 | unsigned long value; |
1234 | char *rest; | 1297 | char *rest; |
1298 | int err; | ||
1299 | unsigned char old_softrepeat, old_softraw; | ||
1235 | 1300 | ||
1236 | if (!atkbd->write) | 1301 | if (!atkbd->write) |
1237 | return -EIO; | 1302 | return -EIO; |
@@ -1241,15 +1306,32 @@ static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t | |||
1241 | return -EINVAL; | 1306 | return -EINVAL; |
1242 | 1307 | ||
1243 | if (atkbd->softrepeat != value) { | 1308 | if (atkbd->softrepeat != value) { |
1244 | if (!(new_dev = input_allocate_device())) | 1309 | old_dev = atkbd->dev; |
1310 | old_softrepeat = atkbd->softrepeat; | ||
1311 | old_softraw = atkbd->softraw; | ||
1312 | |||
1313 | new_dev = input_allocate_device(); | ||
1314 | if (!new_dev) | ||
1245 | return -ENOMEM; | 1315 | return -ENOMEM; |
1246 | input_unregister_device(atkbd->dev); | 1316 | |
1247 | atkbd->dev = new_dev; | 1317 | atkbd->dev = new_dev; |
1248 | atkbd->softrepeat = value; | 1318 | atkbd->softrepeat = value; |
1249 | if (atkbd->softrepeat) | 1319 | if (atkbd->softrepeat) |
1250 | atkbd->softraw = 1; | 1320 | atkbd->softraw = 1; |
1251 | atkbd_set_device_attrs(atkbd); | 1321 | atkbd_set_device_attrs(atkbd); |
1252 | input_register_device(atkbd->dev); | 1322 | |
1323 | err = input_register_device(atkbd->dev); | ||
1324 | if (err) { | ||
1325 | input_free_device(new_dev); | ||
1326 | |||
1327 | atkbd->dev = old_dev; | ||
1328 | atkbd->softrepeat = old_softrepeat; | ||
1329 | atkbd->softraw = old_softraw; | ||
1330 | atkbd_set_device_attrs(atkbd); | ||
1331 | |||
1332 | return err; | ||
1333 | } | ||
1334 | input_unregister_device(old_dev); | ||
1253 | } | 1335 | } |
1254 | return count; | 1336 | return count; |
1255 | } | 1337 | } |
@@ -1262,22 +1344,39 @@ static ssize_t atkbd_show_softraw(struct atkbd *atkbd, char *buf) | |||
1262 | 1344 | ||
1263 | static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t count) | 1345 | static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t count) |
1264 | { | 1346 | { |
1265 | struct input_dev *new_dev; | 1347 | struct input_dev *old_dev, *new_dev; |
1266 | unsigned long value; | 1348 | unsigned long value; |
1267 | char *rest; | 1349 | char *rest; |
1350 | int err; | ||
1351 | unsigned char old_softraw; | ||
1268 | 1352 | ||
1269 | value = simple_strtoul(buf, &rest, 10); | 1353 | value = simple_strtoul(buf, &rest, 10); |
1270 | if (*rest || value > 1) | 1354 | if (*rest || value > 1) |
1271 | return -EINVAL; | 1355 | return -EINVAL; |
1272 | 1356 | ||
1273 | if (atkbd->softraw != value) { | 1357 | if (atkbd->softraw != value) { |
1274 | if (!(new_dev = input_allocate_device())) | 1358 | old_dev = atkbd->dev; |
1359 | old_softraw = atkbd->softraw; | ||
1360 | |||
1361 | new_dev = input_allocate_device(); | ||
1362 | if (!new_dev) | ||
1275 | return -ENOMEM; | 1363 | return -ENOMEM; |
1276 | input_unregister_device(atkbd->dev); | 1364 | |
1277 | atkbd->dev = new_dev; | 1365 | atkbd->dev = new_dev; |
1278 | atkbd->softraw = value; | 1366 | atkbd->softraw = value; |
1279 | atkbd_set_device_attrs(atkbd); | 1367 | atkbd_set_device_attrs(atkbd); |
1280 | input_register_device(atkbd->dev); | 1368 | |
1369 | err = input_register_device(atkbd->dev); | ||
1370 | if (err) { | ||
1371 | input_free_device(new_dev); | ||
1372 | |||
1373 | atkbd->dev = old_dev; | ||
1374 | atkbd->softraw = old_softraw; | ||
1375 | atkbd_set_device_attrs(atkbd); | ||
1376 | |||
1377 | return err; | ||
1378 | } | ||
1379 | input_unregister_device(old_dev); | ||
1281 | } | 1380 | } |
1282 | return count; | 1381 | return count; |
1283 | } | 1382 | } |