V4L/DVB (4854): Handle errors from input_register_device()

Also sprinkled some input_sync() throughout the code.
Acked-by: Ricardo Cerqueira <v4l@cerqueira.org>
Acked-by: Oliver Endriss <o.endriss@gmx.de>
Acked-by: Andrew de Quincey <adq_dvb@lidskialf.net>

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c
index 933d6db..cbc012f 100644
--- a/drivers/media/video/bt8xx/bttv-input.c
+++ b/drivers/media/video/bt8xx/bttv-input.c
@@ -259,24 +259,59 @@
 
 /* ---------------------------------------------------------------------- */
 
+static void bttv_ir_start(struct bttv *btv, struct bttv_ir *ir)
+{
+	if (ir->polling) {
+		init_timer(&ir->timer);
+		ir->timer.function = bttv_input_timer;
+		ir->timer.data     = (unsigned long)btv;
+		ir->timer.expires  = jiffies + HZ;
+		add_timer(&ir->timer);
+	} else if (ir->rc5_gpio) {
+		/* set timer_end for code completion */
+		init_timer(&ir->timer_end);
+		ir->timer_end.function = bttv_rc5_timer_end;
+		ir->timer_end.data = (unsigned long)ir;
+
+		init_timer(&ir->timer_keyup);
+		ir->timer_keyup.function = bttv_rc5_timer_keyup;
+		ir->timer_keyup.data = (unsigned long)ir;
+	}
+}
+
+static void bttv_ir_stop(struct bttv *btv)
+{
+	if (btv->remote->polling) {
+		del_timer_sync(&btv->remote->timer);
+		flush_scheduled_work();
+	}
+
+	if (btv->remote->rc5_gpio) {
+		u32 gpio;
+
+		del_timer_sync(&btv->remote->timer_end);
+		flush_scheduled_work();
+
+		gpio = bttv_gpio_read(&btv->c);
+		bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
+	}
+}
+
 int bttv_input_init(struct bttv *btv)
 {
 	struct bttv_ir *ir;
 	IR_KEYTAB_TYPE *ir_codes = NULL;
 	struct input_dev *input_dev;
 	int ir_type = IR_TYPE_OTHER;
+	int err = -ENOMEM;
 
 	if (!btv->has_remote)
 		return -ENODEV;
 
 	ir = kzalloc(sizeof(*ir),GFP_KERNEL);
 	input_dev = input_allocate_device();
-	if (!ir || !input_dev) {
-		kfree(ir);
-		input_free_device(input_dev);
-		return -ENOMEM;
-	}
-	memset(ir,0,sizeof(*ir));
+	if (!ir || !input_dev)
+		goto err_out_free;
 
 	/* detect & configure */
 	switch (btv->c.type) {
@@ -348,10 +383,9 @@
 		break;
 	}
 	if (NULL == ir_codes) {
-		dprintk(KERN_INFO "Ooops: IR config error [card=%d]\n",btv->c.type);
-		kfree(ir);
-		input_free_device(input_dev);
-		return -ENODEV;
+		dprintk(KERN_INFO "Ooops: IR config error [card=%d]\n", btv->c.type);
+		err = -ENODEV;
+		goto err_out_free;
 	}
 
 	if (ir->rc5_gpio) {
@@ -389,32 +423,26 @@
 	input_dev->cdev.dev = &btv->c.pci->dev;
 
 	btv->remote = ir;
-	if (ir->polling) {
-		init_timer(&ir->timer);
-		ir->timer.function = bttv_input_timer;
-		ir->timer.data     = (unsigned long)btv;
-		ir->timer.expires  = jiffies + HZ;
-		add_timer(&ir->timer);
-	} else if (ir->rc5_gpio) {
-		/* set timer_end for code completion */
-		init_timer(&ir->timer_end);
-		ir->timer_end.function = bttv_rc5_timer_end;
-		ir->timer_end.data = (unsigned long)ir;
-
-		init_timer(&ir->timer_keyup);
-		ir->timer_keyup.function = bttv_rc5_timer_keyup;
-		ir->timer_keyup.data = (unsigned long)ir;
-	}
+	bttv_ir_start(btv, ir);
 
 	/* all done */
-	input_register_device(btv->remote->dev);
-	printk(DEVNAME ": %s detected at %s\n",ir->name,ir->phys);
+	err = input_register_device(btv->remote->dev);
+	if (err)
+		goto err_out_stop;
 
 	/* the remote isn't as bouncy as a keyboard */
 	ir->dev->rep[REP_DELAY] = repeat_delay;
 	ir->dev->rep[REP_PERIOD] = repeat_period;
 
 	return 0;
+
+ err_out_stop:
+	bttv_ir_stop(btv);
+	btv->remote = NULL;
+ err_out_free:
+	input_free_device(input_dev);
+	kfree(ir);
+	return err;
 }
 
 void bttv_input_fini(struct bttv *btv)
@@ -422,22 +450,7 @@
 	if (btv->remote == NULL)
 		return;
 
-	if (btv->remote->polling) {
-		del_timer_sync(&btv->remote->timer);
-		flush_scheduled_work();
-	}
-
-
-	if (btv->remote->rc5_gpio) {
-		u32 gpio;
-
-		del_timer_sync(&btv->remote->timer_end);
-		flush_scheduled_work();
-
-		gpio = bttv_gpio_read(&btv->c);
-		bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
-	}
-
+	bttv_ir_stop(btv);
 	input_unregister_device(btv->remote->dev);
 	kfree(btv->remote);
 	btv->remote = NULL;