Input: keyboards - handle errors when registering input devices
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
This commit is contained in:
@@ -939,7 +939,7 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
|
||||
atkbd = kzalloc(sizeof(struct atkbd), GFP_KERNEL);
|
||||
dev = input_allocate_device();
|
||||
if (!atkbd || !dev)
|
||||
goto fail;
|
||||
goto fail1;
|
||||
|
||||
atkbd->dev = dev;
|
||||
ps2_init(&atkbd->ps2dev, serio);
|
||||
@@ -967,14 +967,13 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
|
||||
|
||||
err = serio_open(serio, drv);
|
||||
if (err)
|
||||
goto fail;
|
||||
goto fail2;
|
||||
|
||||
if (atkbd->write) {
|
||||
|
||||
if (atkbd_probe(atkbd)) {
|
||||
serio_close(serio);
|
||||
err = -ENODEV;
|
||||
goto fail;
|
||||
goto fail3;
|
||||
}
|
||||
|
||||
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)
|
||||
atkbd_set_keycode_table(atkbd);
|
||||
atkbd_set_device_attrs(atkbd);
|
||||
|
||||
sysfs_create_group(&serio->dev.kobj, &atkbd_attribute_group);
|
||||
err = sysfs_create_group(&serio->dev.kobj, &atkbd_attribute_group);
|
||||
if (err)
|
||||
goto fail3;
|
||||
|
||||
atkbd_enable(atkbd);
|
||||
|
||||
input_register_device(atkbd->dev);
|
||||
err = input_register_device(atkbd->dev);
|
||||
if (err)
|
||||
goto fail4;
|
||||
|
||||
return 0;
|
||||
|
||||
fail: serio_set_drvdata(serio, NULL);
|
||||
input_free_device(dev);
|
||||
fail4: sysfs_remove_group(&serio->dev.kobj, &atkbd_attribute_group);
|
||||
fail3: serio_close(serio);
|
||||
fail2: serio_set_drvdata(serio, NULL);
|
||||
fail1: input_free_device(dev);
|
||||
kfree(atkbd);
|
||||
return err;
|
||||
}
|
||||
@@ -1133,9 +1138,11 @@ static ssize_t atkbd_show_extra(struct atkbd *atkbd, char *buf)
|
||||
|
||||
static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t count)
|
||||
{
|
||||
struct input_dev *new_dev;
|
||||
struct input_dev *old_dev, *new_dev;
|
||||
unsigned long value;
|
||||
char *rest;
|
||||
int err;
|
||||
unsigned char old_extra, old_set;
|
||||
|
||||
if (!atkbd->write)
|
||||
return -EIO;
|
||||
@@ -1147,17 +1154,36 @@ static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t coun
|
||||
if (atkbd->extra != value) {
|
||||
/*
|
||||
* Since device's properties will change we need to
|
||||
* unregister old device. But allocate new one first
|
||||
* to make sure we have it.
|
||||
* unregister old device. But allocate and register
|
||||
* new one first to make sure we have it.
|
||||
*/
|
||||
if (!(new_dev = input_allocate_device()))
|
||||
old_dev = atkbd->dev;
|
||||
old_extra = atkbd->extra;
|
||||
old_set = atkbd->set;
|
||||
|
||||
new_dev = input_allocate_device();
|
||||
if (!new_dev)
|
||||
return -ENOMEM;
|
||||
input_unregister_device(atkbd->dev);
|
||||
|
||||
atkbd->dev = new_dev;
|
||||
atkbd->set = atkbd_select_set(atkbd, atkbd->set, value);
|
||||
atkbd_activate(atkbd);
|
||||
atkbd_set_keycode_table(atkbd);
|
||||
atkbd_set_device_attrs(atkbd);
|
||||
input_register_device(atkbd->dev);
|
||||
|
||||
err = input_register_device(atkbd->dev);
|
||||
if (err) {
|
||||
input_free_device(new_dev);
|
||||
|
||||
atkbd->dev = old_dev;
|
||||
atkbd->set = atkbd_select_set(atkbd, old_set, old_extra);
|
||||
atkbd_set_keycode_table(atkbd);
|
||||
atkbd_set_device_attrs(atkbd);
|
||||
|
||||
return err;
|
||||
}
|
||||
input_unregister_device(old_dev);
|
||||
|
||||
}
|
||||
return count;
|
||||
}
|
||||
@@ -1169,23 +1195,41 @@ static ssize_t atkbd_show_scroll(struct atkbd *atkbd, char *buf)
|
||||
|
||||
static ssize_t atkbd_set_scroll(struct atkbd *atkbd, const char *buf, size_t count)
|
||||
{
|
||||
struct input_dev *new_dev;
|
||||
struct input_dev *old_dev, *new_dev;
|
||||
unsigned long value;
|
||||
char *rest;
|
||||
int err;
|
||||
unsigned char old_scroll;
|
||||
|
||||
value = simple_strtoul(buf, &rest, 10);
|
||||
if (*rest || value > 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (atkbd->scroll != value) {
|
||||
if (!(new_dev = input_allocate_device()))
|
||||
old_dev = atkbd->dev;
|
||||
old_scroll = atkbd->scroll;
|
||||
|
||||
new_dev = input_allocate_device();
|
||||
if (!new_dev)
|
||||
return -ENOMEM;
|
||||
input_unregister_device(atkbd->dev);
|
||||
|
||||
atkbd->dev = new_dev;
|
||||
atkbd->scroll = value;
|
||||
atkbd_set_keycode_table(atkbd);
|
||||
atkbd_set_device_attrs(atkbd);
|
||||
input_register_device(atkbd->dev);
|
||||
|
||||
err = input_register_device(atkbd->dev);
|
||||
if (err) {
|
||||
input_free_device(new_dev);
|
||||
|
||||
atkbd->scroll = old_scroll;
|
||||
atkbd->dev = old_dev;
|
||||
atkbd_set_keycode_table(atkbd);
|
||||
atkbd_set_device_attrs(atkbd);
|
||||
|
||||
return err;
|
||||
}
|
||||
input_unregister_device(old_dev);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
@@ -1197,9 +1241,11 @@ static ssize_t atkbd_show_set(struct atkbd *atkbd, char *buf)
|
||||
|
||||
static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count)
|
||||
{
|
||||
struct input_dev *new_dev;
|
||||
struct input_dev *old_dev, *new_dev;
|
||||
unsigned long value;
|
||||
char *rest;
|
||||
int err;
|
||||
unsigned char old_set, old_extra;
|
||||
|
||||
if (!atkbd->write)
|
||||
return -EIO;
|
||||
@@ -1209,15 +1255,32 @@ static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count)
|
||||
return -EINVAL;
|
||||
|
||||
if (atkbd->set != value) {
|
||||
if (!(new_dev = input_allocate_device()))
|
||||
old_dev = atkbd->dev;
|
||||
old_extra = atkbd->extra;
|
||||
old_set = atkbd->set;
|
||||
|
||||
new_dev = input_allocate_device();
|
||||
if (!new_dev)
|
||||
return -ENOMEM;
|
||||
input_unregister_device(atkbd->dev);
|
||||
|
||||
atkbd->dev = new_dev;
|
||||
atkbd->set = atkbd_select_set(atkbd, value, atkbd->extra);
|
||||
atkbd_activate(atkbd);
|
||||
atkbd_set_keycode_table(atkbd);
|
||||
atkbd_set_device_attrs(atkbd);
|
||||
input_register_device(atkbd->dev);
|
||||
|
||||
err = input_register_device(atkbd->dev);
|
||||
if (err) {
|
||||
input_free_device(new_dev);
|
||||
|
||||
atkbd->dev = old_dev;
|
||||
atkbd->set = atkbd_select_set(atkbd, old_set, old_extra);
|
||||
atkbd_set_keycode_table(atkbd);
|
||||
atkbd_set_device_attrs(atkbd);
|
||||
|
||||
return err;
|
||||
}
|
||||
input_unregister_device(old_dev);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
@@ -1229,9 +1292,11 @@ static ssize_t atkbd_show_softrepeat(struct atkbd *atkbd, char *buf)
|
||||
|
||||
static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t count)
|
||||
{
|
||||
struct input_dev *new_dev;
|
||||
struct input_dev *old_dev, *new_dev;
|
||||
unsigned long value;
|
||||
char *rest;
|
||||
int err;
|
||||
unsigned char old_softrepeat, old_softraw;
|
||||
|
||||
if (!atkbd->write)
|
||||
return -EIO;
|
||||
@@ -1241,15 +1306,32 @@ static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t
|
||||
return -EINVAL;
|
||||
|
||||
if (atkbd->softrepeat != value) {
|
||||
if (!(new_dev = input_allocate_device()))
|
||||
old_dev = atkbd->dev;
|
||||
old_softrepeat = atkbd->softrepeat;
|
||||
old_softraw = atkbd->softraw;
|
||||
|
||||
new_dev = input_allocate_device();
|
||||
if (!new_dev)
|
||||
return -ENOMEM;
|
||||
input_unregister_device(atkbd->dev);
|
||||
|
||||
atkbd->dev = new_dev;
|
||||
atkbd->softrepeat = value;
|
||||
if (atkbd->softrepeat)
|
||||
atkbd->softraw = 1;
|
||||
atkbd_set_device_attrs(atkbd);
|
||||
input_register_device(atkbd->dev);
|
||||
|
||||
err = input_register_device(atkbd->dev);
|
||||
if (err) {
|
||||
input_free_device(new_dev);
|
||||
|
||||
atkbd->dev = old_dev;
|
||||
atkbd->softrepeat = old_softrepeat;
|
||||
atkbd->softraw = old_softraw;
|
||||
atkbd_set_device_attrs(atkbd);
|
||||
|
||||
return err;
|
||||
}
|
||||
input_unregister_device(old_dev);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
@@ -1262,22 +1344,39 @@ static ssize_t atkbd_show_softraw(struct atkbd *atkbd, char *buf)
|
||||
|
||||
static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t count)
|
||||
{
|
||||
struct input_dev *new_dev;
|
||||
struct input_dev *old_dev, *new_dev;
|
||||
unsigned long value;
|
||||
char *rest;
|
||||
int err;
|
||||
unsigned char old_softraw;
|
||||
|
||||
value = simple_strtoul(buf, &rest, 10);
|
||||
if (*rest || value > 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (atkbd->softraw != value) {
|
||||
if (!(new_dev = input_allocate_device()))
|
||||
old_dev = atkbd->dev;
|
||||
old_softraw = atkbd->softraw;
|
||||
|
||||
new_dev = input_allocate_device();
|
||||
if (!new_dev)
|
||||
return -ENOMEM;
|
||||
input_unregister_device(atkbd->dev);
|
||||
|
||||
atkbd->dev = new_dev;
|
||||
atkbd->softraw = value;
|
||||
atkbd_set_device_attrs(atkbd);
|
||||
input_register_device(atkbd->dev);
|
||||
|
||||
err = input_register_device(atkbd->dev);
|
||||
if (err) {
|
||||
input_free_device(new_dev);
|
||||
|
||||
atkbd->dev = old_dev;
|
||||
atkbd->softraw = old_softraw;
|
||||
atkbd_set_device_attrs(atkbd);
|
||||
|
||||
return err;
|
||||
}
|
||||
input_unregister_device(old_dev);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
Reference in New Issue
Block a user