int i, j;
 
        if (!AMIGAHW_PRESENT(AMI_KEYBOARD))
-               return -EIO;
+               return -ENODEV;
 
        if (!request_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100, "amikeyb"))
                return -EBUSY;
        amikbd_dev = input_allocate_device();
        if (!amikbd_dev) {
                printk(KERN_ERR "amikbd: not enough memory for input device\n");
-               release_mem_region(CIAA_PHYSADDR - 1 + 0xb00, 0x100);
-               return -ENOMEM;
+               err = -ENOMEM;
+               goto fail1;
        }
 
        amikbd_dev->name = "Amiga Keyboard";
                memcpy(key_maps[i], temp_map, sizeof(temp_map));
        }
        ciaa.cra &= ~0x41;       /* serial data in, turn off TA */
-       request_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt, 0, "amikbd", amikbd_interrupt);
+       if (request_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt, 0, "amikbd",
+                       amikbd_interrupt)) {
+               err = -EBUSY;
+               goto fail2;
+       }
+
+       err = input_register_device(amikbd_dev);
+       if (err)
+               goto fail3;
 
-       input_register_device(amikbd_dev);
        return 0;
+
+ fail3:        free_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt);
+ fail2:        input_free_device(amikbd_dev);
+ fail1:        release_mem_region(CIAA_PHYSADDR - 1 + 0xb00, 0x100);
+       return err;
 }
 
 static void __exit amikbd_exit(void)
 
        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);
 
        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);
        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;
 }
 
 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;
        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;
 }
 
 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;
 }
 
 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;
                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;
 }
 
 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;
                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;
 }
 
 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;
 }
 
 {
        struct corgikbd *corgikbd;
        struct input_dev *input_dev;
-       int i;
+       int i, err = -ENOMEM;
 
        corgikbd = kzalloc(sizeof(struct corgikbd), GFP_KERNEL);
        input_dev = input_allocate_device();
-       if (!corgikbd || !input_dev) {
-               kfree(corgikbd);
-               input_free_device(input_dev);
-               return -ENOMEM;
-       }
+       if (!corgikbd || !input_dev)
+               goto fail;
 
        platform_set_drvdata(pdev, corgikbd);
 
        set_bit(SW_TABLET_MODE, input_dev->swbit);
        set_bit(SW_HEADPHONE_INSERT, input_dev->swbit);
 
-       input_register_device(corgikbd->input);
+       err = input_register_device(corgikbd->input);
+       if (err)
+               goto fail;
 
        mod_timer(&corgikbd->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL));
 
        pxa_gpio_mode(CORGI_GPIO_AK_INT | GPIO_IN);
 
        return 0;
+
+ fail: input_free_device(input_dev);
+       kfree(corgikbd);
+       return err;
 }
 
 static int corgikbd_remove(struct platform_device *pdev)
 
        input_dev = input_allocate_device ();
        if (!lk || !input_dev) {
                err = -ENOMEM;
-               goto fail;
+               goto fail1;
        }
 
        lk->serio = serio;
 
        err = serio_open (serio, drv);
        if (err)
-               goto fail;
+               goto fail2;
+
+       err = input_register_device (lk->dev);
+       if (err)
+               goto fail3;
 
-       input_register_device (lk->dev);
        lk->serio->write (lk->serio, LK_CMD_POWERCYCLE_RESET);
 
        return 0;
 
- fail: serio_set_drvdata (serio, NULL);
-       input_free_device (input_dev);
+ fail3:        serio_close (serio);
+ fail2:        serio_set_drvdata (serio, NULL);
+ fail1:        input_free_device (input_dev);
        kfree (lk);
        return err;
 }
 
 {
        struct locomokbd *locomokbd;
        struct input_dev *input_dev;
-       int i, ret;
+       int i, err;
 
        locomokbd = kzalloc(sizeof(struct locomokbd), GFP_KERNEL);
        input_dev = input_allocate_device();
        if (!locomokbd || !input_dev) {
-               ret = -ENOMEM;
-               goto free;
+               err = -ENOMEM;
+               goto err_free_mem;
        }
 
        /* try and claim memory region */
        if (!request_mem_region((unsigned long) dev->mapbase,
                                dev->length,
                                LOCOMO_DRIVER_NAME(dev))) {
-               ret = -EBUSY;
+               err = -EBUSY;
                printk(KERN_ERR "locomokbd: Can't acquire access to io memory for keyboard\n");
-               goto free;
+               goto err_free_mem;
        }
 
        locomokbd->ldev = dev;
        clear_bit(0, input_dev->keybit);
 
        /* attempt to get the interrupt */
-       ret = request_irq(dev->irq[0], locomokbd_interrupt, 0, "locomokbd", locomokbd);
-       if (ret) {
+       err = request_irq(dev->irq[0], locomokbd_interrupt, 0, "locomokbd", locomokbd);
+       if (err) {
                printk(KERN_ERR "locomokbd: Can't get irq for keyboard\n");
-               goto out;
+               goto err_release_region;
        }
 
-       input_register_device(locomokbd->input);
+       err = input_register_device(locomokbd->input);
+       if (err)
+               goto err_free_irq;
 
        return 0;
 
-out:
+ err_free_irq:
+       free_irq(dev->irq[0], locomokbd);
+ err_release_region:
        release_mem_region((unsigned long) dev->mapbase, dev->length);
        locomo_set_drvdata(dev, NULL);
-free:
+ err_free_mem:
        input_free_device(input_dev);
        kfree(locomokbd);
 
-       return ret;
+       return err;
 }
 
 static int locomokbd_remove(struct locomo_dev *dev)
 
        struct input_dev *input_dev;
        unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]);
        int i;
+       int err;
 
        dev->private_data = kbd = kzalloc(sizeof(struct dc_kbd), GFP_KERNEL);
        input_dev = input_allocate_device();
        if (!kbd || !input_dev) {
-               kfree(kbd);
-               input_free_device(input_dev);
-               return -ENOMEM;
+               err = -ENOMEM;
+               goto fail;
        }
 
        kbd->dev = input_dev;
                set_bit(dc_kbd_keycode[i], input_dev->keybit);
        clear_bit(0, input_dev->keybit);
 
-       input_register_device(kbd->dev);
+       err = input_register_device(kbd->dev);
+       if (err)
+               goto fail;
 
        maple_getcond_callback(dev, dc_kbd_callback, 1, MAPLE_FUNC_KEYBOARD);
        return 0;
+
+ fail: input_free_device(input_dev);
+       kfree(kbd);
+       return err;
 }
 
 
 
        nkbd = kzalloc(sizeof(struct nkbd), GFP_KERNEL);
        input_dev = input_allocate_device();
        if (!nkbd || !input_dev)
-               goto fail;
+               goto fail1;
 
        nkbd->serio = serio;
        nkbd->dev = input_dev;
 
        err = serio_open(serio, drv);
        if (err)
-               goto fail;
+               goto fail2;
+
+       err = input_register_device(nkbd->dev);
+       if (err)
+               goto fail3;
 
-       input_register_device(nkbd->dev);
        return 0;
 
- fail: serio_set_drvdata(serio, NULL);
-       input_free_device(input_dev);
+ fail3:        serio_close(serio);
+ fail2:        serio_set_drvdata(serio, NULL);
+ fail1:        input_free_device(input_dev);
        kfree(nkbd);
        return err;
 }
 
 {
        struct spitzkbd *spitzkbd;
        struct input_dev *input_dev;
-       int i;
+       int i, err = -ENOMEM;
 
        spitzkbd = kzalloc(sizeof(struct spitzkbd), GFP_KERNEL);
-       if (!spitzkbd)
-               return -ENOMEM;
-
        input_dev = input_allocate_device();
-       if (!input_dev) {
-               kfree(spitzkbd);
-               return -ENOMEM;
-       }
+       if (!spitzkbd || !input_dev)
+               goto fail;
 
        platform_set_drvdata(dev, spitzkbd);
        strcpy(spitzkbd->phys, "spitzkbd/input0");
        set_bit(SW_TABLET_MODE, input_dev->swbit);
        set_bit(SW_HEADPHONE_INSERT, input_dev->swbit);
 
-       input_register_device(input_dev);
+       err = input_register_device(input_dev);
+       if (err)
+               goto fail;
 
        mod_timer(&spitzkbd->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL));
 
        request_irq(SPITZ_IRQ_GPIO_SWB, spitzkbd_hinge_isr,
                    IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
                    "Spitzkbd SWB", spitzkbd);
-       request_irq(SPITZ_IRQ_GPIO_AK_INT, spitzkbd_hinge_isr,
+       request_irq(SPITZ_IRQ_GPIO_AK_INT, spitzkbd_hinge_isr,
                    IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
                    "Spitzkbd HP", spitzkbd);
 
-       printk(KERN_INFO "input: Spitz Keyboard Registered\n");
-
        return 0;
+
+ fail: input_free_device(input_dev);
+       kfree(spitzkbd);
+       return err;
 }
 
 static int spitzkbd_remove(struct platform_device *dev)
        .resume         = spitzkbd_resume,
        .driver         = {
                .name   = "spitz-keyboard",
+               .owner  = THIS_MODULE,
        },
 };
 
 
        sunkbd = kzalloc(sizeof(struct sunkbd), GFP_KERNEL);
        input_dev = input_allocate_device();
        if (!sunkbd || !input_dev)
-               goto fail;
+               goto fail1;
 
        sunkbd->serio = serio;
        sunkbd->dev = input_dev;
 
        err = serio_open(serio, drv);
        if (err)
-               goto fail;
+               goto fail2;
 
        if (sunkbd_initialize(sunkbd) < 0) {
-               serio_close(serio);
-               goto fail;
+               err = -ENODEV;
+               goto fail3;
        }
 
        snprintf(sunkbd->name, sizeof(sunkbd->name), "Sun Type %d keyboard", sunkbd->type);
        clear_bit(0, input_dev->keybit);
 
        sunkbd_enable(sunkbd, 1);
-       input_register_device(sunkbd->dev);
+
+       err = input_register_device(sunkbd->dev);
+       if (err)
+               goto fail4;
+
        return 0;
 
- fail: serio_set_drvdata(serio, NULL);
-       input_free_device(input_dev);
+ fail4:        sunkbd_enable(sunkbd, 0);
+ fail3:        serio_close(serio);
+ fail2:        serio_set_drvdata(serio, NULL);
+ fail1:        input_free_device(input_dev);
        kfree(sunkbd);
        return err;
 }
 
        xtkbd = kmalloc(sizeof(struct xtkbd), GFP_KERNEL);
        input_dev = input_allocate_device();
        if (!xtkbd || !input_dev)
-               goto fail;
+               goto fail1;
 
        xtkbd->serio = serio;
        xtkbd->dev = input_dev;
 
        err = serio_open(serio, drv);
        if (err)
-               goto fail;
+               goto fail2;
+
+       err = input_register_device(xtkbd->dev);
+       if (err)
+               goto fail3;
 
-       input_register_device(xtkbd->dev);
        return 0;
 
- fail: serio_set_drvdata(serio, NULL);
-       input_free_device(input_dev);
+ fail3:        serio_close(serio);
+ fail2:        serio_set_drvdata(serio, NULL);
+ fail1:        input_free_device(input_dev);
        kfree(xtkbd);
        return err;
 }