dect
/
linux-2.6
Archived
13
0
Fork 0

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>
This commit is contained in:
Dmitry Torokhov 2006-11-20 10:23:04 -03:00 committed by Mauro Carvalho Chehab
parent ff67c614e2
commit b07b4783fb
10 changed files with 257 additions and 149 deletions

View File

@ -746,6 +746,7 @@ static void cinergyt2_query_rc (struct work_struct *work)
dprintk(1, "rc_input_event=%d Up\n", cinergyt2->rc_input_event); dprintk(1, "rc_input_event=%d Up\n", cinergyt2->rc_input_event);
input_report_key(cinergyt2->rc_input_dev, input_report_key(cinergyt2->rc_input_dev,
cinergyt2->rc_input_event, 0); cinergyt2->rc_input_event, 0);
input_sync(cinergyt2->rc_input_dev);
cinergyt2->rc_input_event = KEY_MAX; cinergyt2->rc_input_event = KEY_MAX;
} }
cinergyt2->rc_last_code = ~0; cinergyt2->rc_last_code = ~0;
@ -783,6 +784,7 @@ static void cinergyt2_query_rc (struct work_struct *work)
dprintk(1, "rc_input_event=%d\n", cinergyt2->rc_input_event); dprintk(1, "rc_input_event=%d\n", cinergyt2->rc_input_event);
input_report_key(cinergyt2->rc_input_dev, input_report_key(cinergyt2->rc_input_dev,
cinergyt2->rc_input_event, 1); cinergyt2->rc_input_event, 1);
input_sync(cinergyt2->rc_input_dev);
cinergyt2->rc_last_code = rc_events[n].value; cinergyt2->rc_last_code = rc_events[n].value;
} }
} }
@ -798,8 +800,9 @@ static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2)
{ {
struct input_dev *input_dev; struct input_dev *input_dev;
int i; int i;
int err;
cinergyt2->rc_input_dev = input_dev = input_allocate_device(); input_dev = input_allocate_device();
if (!input_dev) if (!input_dev)
return -ENOMEM; return -ENOMEM;
@ -817,7 +820,13 @@ static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2)
input_dev->keycodesize = 0; input_dev->keycodesize = 0;
input_dev->keycodemax = 0; input_dev->keycodemax = 0;
input_register_device(cinergyt2->rc_input_dev); err = input_register_device(input_dev);
if (err) {
input_free_device(input_dev);
return err;
}
cinergyt2->rc_input_dev = input_dev;
schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2); schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2);
return 0; return 0;

View File

@ -90,7 +90,9 @@ schedule:
int dvb_usb_remote_init(struct dvb_usb_device *d) int dvb_usb_remote_init(struct dvb_usb_device *d)
{ {
struct input_dev *input_dev;
int i; int i;
int err;
if (d->props.rc_key_map == NULL || if (d->props.rc_key_map == NULL ||
d->props.rc_query == NULL || d->props.rc_query == NULL ||
@ -100,23 +102,24 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)
usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys)); strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
d->rc_input_dev = input_allocate_device(); input_dev = input_allocate_device();
if (!d->rc_input_dev) if (!input_dev)
return -ENOMEM; return -ENOMEM;
d->rc_input_dev->evbit[0] = BIT(EV_KEY); input_dev->evbit[0] = BIT(EV_KEY);
d->rc_input_dev->keycodesize = sizeof(unsigned char); input_dev->keycodesize = sizeof(unsigned char);
d->rc_input_dev->keycodemax = KEY_MAX; input_dev->keycodemax = KEY_MAX;
d->rc_input_dev->name = "IR-receiver inside an USB DVB receiver"; input_dev->name = "IR-receiver inside an USB DVB receiver";
d->rc_input_dev->phys = d->rc_phys; input_dev->phys = d->rc_phys;
usb_to_input_id(d->udev, &d->rc_input_dev->id); usb_to_input_id(d->udev, &input_dev->id);
d->rc_input_dev->cdev.dev = &d->udev->dev; input_dev->cdev.dev = &d->udev->dev;
/* set the bits for the keys */ /* set the bits for the keys */
deb_rc("key map size: %d\n", d->props.rc_key_map_size); deb_rc("key map size: %d\n", d->props.rc_key_map_size);
for (i = 0; i < d->props.rc_key_map_size; i++) { for (i = 0; i < d->props.rc_key_map_size; i++) {
deb_rc("setting bit for event %d item %d\n",d->props.rc_key_map[i].event, i); deb_rc("setting bit for event %d item %d\n",
set_bit(d->props.rc_key_map[i].event, d->rc_input_dev->keybit); d->props.rc_key_map[i].event, i);
set_bit(d->props.rc_key_map[i].event, input_dev->keybit);
} }
/* Start the remote-control polling. */ /* Start the remote-control polling. */
@ -124,10 +127,16 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)
d->props.rc_interval = 100; /* default */ d->props.rc_interval = 100; /* default */
/* setting these two values to non-zero, we have to manage key repeats */ /* setting these two values to non-zero, we have to manage key repeats */
d->rc_input_dev->rep[REP_PERIOD] = d->props.rc_interval; input_dev->rep[REP_PERIOD] = d->props.rc_interval;
d->rc_input_dev->rep[REP_DELAY] = d->props.rc_interval + 150; input_dev->rep[REP_DELAY] = d->props.rc_interval + 150;
input_register_device(d->rc_input_dev); err = input_register_device(input_dev);
if (err) {
input_free_device(input_dev);
return err;
}
d->rc_input_dev = input_dev;
INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control); INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control);

View File

@ -48,7 +48,8 @@ static void av7110_emit_keyup(unsigned long data)
if (!data || !test_bit(data, input_dev->key)) if (!data || !test_bit(data, input_dev->key))
return; return;
input_event(input_dev, EV_KEY, data, !!0); input_report_key(input_dev, data, 0);
input_sync(input_dev);
} }
@ -115,14 +116,17 @@ static void av7110_emit_key(unsigned long parm)
del_timer(&keyup_timer); del_timer(&keyup_timer);
if (keyup_timer.data != keycode || new_toggle != old_toggle) { if (keyup_timer.data != keycode || new_toggle != old_toggle) {
delay_timer_finished = 0; delay_timer_finished = 0;
input_event(input_dev, EV_KEY, keyup_timer.data, !!0); input_event(input_dev, EV_KEY, keyup_timer.data, 0);
input_event(input_dev, EV_KEY, keycode, !0); input_event(input_dev, EV_KEY, keycode, 1);
} else input_sync(input_dev);
if (delay_timer_finished) } else if (delay_timer_finished) {
input_event(input_dev, EV_KEY, keycode, 2); input_event(input_dev, EV_KEY, keycode, 2);
input_sync(input_dev);
}
} else { } else {
delay_timer_finished = 0; delay_timer_finished = 0;
input_event(input_dev, EV_KEY, keycode, !0); input_event(input_dev, EV_KEY, keycode, 1);
input_sync(input_dev);
} }
keyup_timer.expires = jiffies + UP_TIMEOUT; keyup_timer.expires = jiffies + UP_TIMEOUT;
@ -211,6 +215,7 @@ static void ir_handler(struct av7110 *av7110, u32 ircom)
int __devinit av7110_ir_init(struct av7110 *av7110) int __devinit av7110_ir_init(struct av7110 *av7110)
{ {
static struct proc_dir_entry *e; static struct proc_dir_entry *e;
int err;
if (av_cnt >= sizeof av_list/sizeof av_list[0]) if (av_cnt >= sizeof av_list/sizeof av_list[0])
return -ENOSPC; return -ENOSPC;
@ -231,7 +236,11 @@ int __devinit av7110_ir_init(struct av7110 *av7110)
set_bit(EV_KEY, input_dev->evbit); set_bit(EV_KEY, input_dev->evbit);
set_bit(EV_REP, input_dev->evbit); set_bit(EV_REP, input_dev->evbit);
input_register_keys(); input_register_keys();
input_register_device(input_dev); err = input_register_device(input_dev);
if (err) {
input_free_device(input_dev);
return err;
}
input_dev->timer.function = input_repeat_key; input_dev->timer.function = input_repeat_key;
e = create_proc_entry("av7110_ir", S_IFREG | S_IRUGO | S_IWUSR, NULL); e = create_proc_entry("av7110_ir", S_IFREG | S_IRUGO | S_IWUSR, NULL);

View File

@ -143,14 +143,14 @@ static void msp430_ir_debounce(unsigned long data)
struct input_dev *dev = (struct input_dev *) data; struct input_dev *dev = (struct input_dev *) data;
if (dev->rep[0] == 0 || dev->rep[0] == ~0) { if (dev->rep[0] == 0 || dev->rep[0] == ~0) {
input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0); input_event(dev, EV_KEY, key_map[dev->repeat_key], 0);
return; } else {
dev->rep[0] = 0;
dev->timer.expires = jiffies + HZ * 350 / 1000;
add_timer(&dev->timer);
input_event(dev, EV_KEY, key_map[dev->repeat_key], 2); /* REPEAT */
} }
input_sync(dev);
dev->rep[0] = 0;
dev->timer.expires = jiffies + HZ * 350 / 1000;
add_timer(&dev->timer);
input_event(dev, EV_KEY, key_map[dev->repeat_key], 2); /* REPEAT */
} }
static void msp430_ir_interrupt(unsigned long data) static void msp430_ir_interrupt(unsigned long data)
@ -169,7 +169,7 @@ static void msp430_ir_interrupt(unsigned long data)
return; return;
} }
del_timer(&dev->timer); del_timer(&dev->timer);
input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0); input_event(dev, EV_KEY, key_map[dev->repeat_key], 0);
} }
if (!key_map[code]) { if (!key_map[code]) {
@ -177,15 +177,14 @@ static void msp430_ir_interrupt(unsigned long data)
return; return;
} }
input_event(dev, EV_KEY, key_map[code], 1);
input_sync(dev);
/* initialize debounce and repeat */ /* initialize debounce and repeat */
dev->repeat_key = code; dev->repeat_key = code;
/* Zenith remote _always_ sends 2 sequences */ /* Zenith remote _always_ sends 2 sequences */
dev->rep[0] = ~0; dev->rep[0] = ~0;
/* 350 milliseconds */ mod_timer(&dev->timer, jiffies + msecs_to_jiffies(350));
dev->timer.expires = jiffies + HZ * 350 / 1000;
/* MAKE */
input_event(dev, EV_KEY, key_map[code], !0);
add_timer(&dev->timer);
} }
} }
@ -194,8 +193,9 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
struct saa7146_dev *saa = budget_ci->budget.dev; struct saa7146_dev *saa = budget_ci->budget.dev;
struct input_dev *input_dev; struct input_dev *input_dev;
int i; int i;
int err;
budget_ci->input_dev = input_dev = input_allocate_device(); input_dev = input_allocate_device();
if (!input_dev) if (!input_dev)
return -ENOMEM; return -ENOMEM;
@ -208,10 +208,16 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
if (key_map[i]) if (key_map[i])
set_bit(key_map[i], input_dev->keybit); set_bit(key_map[i], input_dev->keybit);
input_register_device(budget_ci->input_dev); err = input_register_device(input_dev);
if (err) {
input_free_device(input_dev);
return err;
}
input_dev->timer.function = msp430_ir_debounce; input_dev->timer.function = msp430_ir_debounce;
budget_ci->input_dev = input_dev;
saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_06); saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_06);
saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI); saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI);
@ -226,8 +232,10 @@ static void msp430_ir_deinit(struct budget_ci *budget_ci)
saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_06); saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_06);
saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
if (del_timer(&dev->timer)) if (del_timer(&dev->timer)) {
input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0); input_event(dev, EV_KEY, key_map[dev->repeat_key], 0);
input_sync(dev);
}
input_unregister_device(dev); input_unregister_device(dev);
} }

View File

@ -238,6 +238,7 @@ static void ttusb_dec_handle_irq( struct urb *urb)
* for now lets report each signal as a key down and up*/ * for now lets report each signal as a key down and up*/
dprintk("%s:rc signal:%d\n", __FUNCTION__, buffer[4]); dprintk("%s:rc signal:%d\n", __FUNCTION__, buffer[4]);
input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 1); input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 1);
input_sync(dec->rc_input_dev);
input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 0); input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 0);
input_sync(dec->rc_input_dev); input_sync(dec->rc_input_dev);
} }
@ -1187,11 +1188,12 @@ static int ttusb_init_rc( struct ttusb_dec *dec)
struct input_dev *input_dev; struct input_dev *input_dev;
u8 b[] = { 0x00, 0x01 }; u8 b[] = { 0x00, 0x01 };
int i; int i;
int err;
usb_make_path(dec->udev, dec->rc_phys, sizeof(dec->rc_phys)); usb_make_path(dec->udev, dec->rc_phys, sizeof(dec->rc_phys));
strlcpy(dec->rc_phys, "/input0", sizeof(dec->rc_phys)); strlcpy(dec->rc_phys, "/input0", sizeof(dec->rc_phys));
dec->rc_input_dev = input_dev = input_allocate_device(); input_dev = input_allocate_device();
if (!input_dev) if (!input_dev)
return -ENOMEM; return -ENOMEM;
@ -1205,8 +1207,13 @@ static int ttusb_init_rc( struct ttusb_dec *dec)
for (i = 0; i < ARRAY_SIZE(rc_keys); i++) for (i = 0; i < ARRAY_SIZE(rc_keys); i++)
set_bit(rc_keys[i], input_dev->keybit); set_bit(rc_keys[i], input_dev->keybit);
input_register_device(input_dev); err = input_register_device(input_dev);
if (err) {
input_free_device(input_dev);
return err;
}
dec->rc_input_dev = input_dev;
if (usb_submit_urb(dec->irq_urb, GFP_KERNEL)) if (usb_submit_urb(dec->irq_urb, GFP_KERNEL))
printk("%s: usb_submit_urb failed\n",__FUNCTION__); printk("%s: usb_submit_urb failed\n",__FUNCTION__);
/* enable irq pipe */ /* enable irq pipe */

View File

@ -259,24 +259,59 @@ static void bttv_rc5_timer_keyup(unsigned long data)
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
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) int bttv_input_init(struct bttv *btv)
{ {
struct bttv_ir *ir; struct bttv_ir *ir;
IR_KEYTAB_TYPE *ir_codes = NULL; IR_KEYTAB_TYPE *ir_codes = NULL;
struct input_dev *input_dev; struct input_dev *input_dev;
int ir_type = IR_TYPE_OTHER; int ir_type = IR_TYPE_OTHER;
int err = -ENOMEM;
if (!btv->has_remote) if (!btv->has_remote)
return -ENODEV; return -ENODEV;
ir = kzalloc(sizeof(*ir),GFP_KERNEL); ir = kzalloc(sizeof(*ir),GFP_KERNEL);
input_dev = input_allocate_device(); input_dev = input_allocate_device();
if (!ir || !input_dev) { if (!ir || !input_dev)
kfree(ir); goto err_out_free;
input_free_device(input_dev);
return -ENOMEM;
}
memset(ir,0,sizeof(*ir));
/* detect & configure */ /* detect & configure */
switch (btv->c.type) { switch (btv->c.type) {
@ -348,10 +383,9 @@ int bttv_input_init(struct bttv *btv)
break; break;
} }
if (NULL == ir_codes) { if (NULL == ir_codes) {
dprintk(KERN_INFO "Ooops: IR config error [card=%d]\n",btv->c.type); dprintk(KERN_INFO "Ooops: IR config error [card=%d]\n", btv->c.type);
kfree(ir); err = -ENODEV;
input_free_device(input_dev); goto err_out_free;
return -ENODEV;
} }
if (ir->rc5_gpio) { if (ir->rc5_gpio) {
@ -389,32 +423,26 @@ int bttv_input_init(struct bttv *btv)
input_dev->cdev.dev = &btv->c.pci->dev; input_dev->cdev.dev = &btv->c.pci->dev;
btv->remote = ir; btv->remote = ir;
if (ir->polling) { bttv_ir_start(btv, ir);
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;
}
/* all done */ /* all done */
input_register_device(btv->remote->dev); err = input_register_device(btv->remote->dev);
printk(DEVNAME ": %s detected at %s\n",ir->name,ir->phys); if (err)
goto err_out_stop;
/* the remote isn't as bouncy as a keyboard */ /* the remote isn't as bouncy as a keyboard */
ir->dev->rep[REP_DELAY] = repeat_delay; ir->dev->rep[REP_DELAY] = repeat_delay;
ir->dev->rep[REP_PERIOD] = repeat_period; ir->dev->rep[REP_PERIOD] = repeat_period;
return 0; 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) void bttv_input_fini(struct bttv *btv)
@ -422,22 +450,7 @@ void bttv_input_fini(struct bttv *btv)
if (btv->remote == NULL) if (btv->remote == NULL)
return; return;
if (btv->remote->polling) { bttv_ir_stop(btv);
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));
}
input_unregister_device(btv->remote->dev); input_unregister_device(btv->remote->dev);
kfree(btv->remote); kfree(btv->remote);
btv->remote = NULL; btv->remote = NULL;

View File

@ -155,6 +155,35 @@ static void cx88_ir_work(struct work_struct *work)
mod_timer(&ir->timer, timeout); mod_timer(&ir->timer, timeout);
} }
static void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir)
{
if (ir->polling) {
INIT_WORK(&ir->work, cx88_ir_work, ir);
init_timer(&ir->timer);
ir->timer.function = ir_timer;
ir->timer.data = (unsigned long)ir;
schedule_work(&ir->work);
}
if (ir->sampling) {
core->pci_irqmask |= (1 << 18); /* IR_SMP_INT */
cx_write(MO_DDS_IO, 0xa80a80); /* 4 kHz sample rate */
cx_write(MO_DDSCFG_IO, 0x5); /* enable */
}
}
static void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir)
{
if (ir->sampling) {
cx_write(MO_DDSCFG_IO, 0x0);
core->pci_irqmask &= ~(1 << 18);
}
if (ir->polling) {
del_timer_sync(&ir->timer);
flush_scheduled_work();
}
}
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
@ -163,14 +192,12 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
struct input_dev *input_dev; struct input_dev *input_dev;
IR_KEYTAB_TYPE *ir_codes = NULL; IR_KEYTAB_TYPE *ir_codes = NULL;
int ir_type = IR_TYPE_OTHER; int ir_type = IR_TYPE_OTHER;
int err = -ENOMEM;
ir = kzalloc(sizeof(*ir), GFP_KERNEL); ir = kzalloc(sizeof(*ir), GFP_KERNEL);
input_dev = input_allocate_device(); input_dev = input_allocate_device();
if (!ir || !input_dev) { if (!ir || !input_dev)
kfree(ir); goto err_out_free;
input_free_device(input_dev);
return -ENOMEM;
}
ir->input = input_dev; ir->input = input_dev;
@ -280,9 +307,8 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
} }
if (NULL == ir_codes) { if (NULL == ir_codes) {
kfree(ir); err = -ENODEV;
input_free_device(input_dev); goto err_out_free;
return -ENODEV;
} }
/* init input device */ /* init input device */
@ -307,23 +333,22 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
ir->core = core; ir->core = core;
core->ir = ir; core->ir = ir;
if (ir->polling) { cx88_ir_start(core, ir);
INIT_WORK(&ir->work, cx88_ir_work);
init_timer(&ir->timer);
ir->timer.function = ir_timer;
ir->timer.data = (unsigned long)ir;
schedule_work(&ir->work);
}
if (ir->sampling) {
core->pci_irqmask |= (1 << 18); /* IR_SMP_INT */
cx_write(MO_DDS_IO, 0xa80a80); /* 4 kHz sample rate */
cx_write(MO_DDSCFG_IO, 0x5); /* enable */
}
/* all done */ /* all done */
input_register_device(ir->input); err = input_register_device(ir->input);
if (err)
goto err_out_stop;
return 0; return 0;
err_out_stop:
cx88_ir_stop(core, ir);
core->ir = NULL;
err_out_free:
input_free_device(input_dev);
kfree(ir);
return err;
} }
int cx88_ir_fini(struct cx88_core *core) int cx88_ir_fini(struct cx88_core *core)
@ -334,15 +359,7 @@ int cx88_ir_fini(struct cx88_core *core)
if (NULL == ir) if (NULL == ir)
return 0; return 0;
if (ir->sampling) { cx88_ir_stop(core, ir);
cx_write(MO_DDSCFG_IO, 0x0);
core->pci_irqmask &= ~(1 << 18);
}
if (ir->polling) {
del_timer(&ir->timer);
flush_scheduled_work();
}
input_unregister_device(ir->input); input_unregister_device(ir->input);
kfree(ir); kfree(ir);

View File

@ -305,15 +305,14 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
int ir_type; int ir_type;
struct IR_i2c *ir; struct IR_i2c *ir;
struct input_dev *input_dev; struct input_dev *input_dev;
int err;
ir = kzalloc(sizeof(struct IR_i2c),GFP_KERNEL); ir = kzalloc(sizeof(struct IR_i2c),GFP_KERNEL);
input_dev = input_allocate_device(); input_dev = input_allocate_device();
if (!ir || !input_dev) { if (!ir || !input_dev) {
input_free_device(input_dev); err = -ENOMEM;
kfree(ir); goto err_out_free;
return -ENOMEM;
} }
memset(ir,0,sizeof(*ir));
ir->c = client_template; ir->c = client_template;
ir->input = input_dev; ir->input = input_dev;
@ -361,26 +360,27 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
break; break;
default: default:
/* shouldn't happen */ /* shouldn't happen */
printk(DEVNAME ": Huh? unknown i2c address (0x%02x)?\n",addr); printk(DEVNAME ": Huh? unknown i2c address (0x%02x)?\n", addr);
kfree(ir); err = -ENODEV;
return -1; goto err_out_free;
} }
/* Sets name */ /* Sets name */
snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (%s)", name); snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (%s)", name);
ir->ir_codes=ir_codes; ir->ir_codes = ir_codes;
/* register i2c device /* register i2c device
* At device register, IR codes may be changed to be * At device register, IR codes may be changed to be
* board dependent. * board dependent.
*/ */
i2c_attach_client(&ir->c); err = i2c_attach_client(&ir->c);
if (err)
goto err_out_free;
/* If IR not supported or disabled, unregisters driver */ /* If IR not supported or disabled, unregisters driver */
if (ir->get_key == NULL) { if (ir->get_key == NULL) {
i2c_detach_client(&ir->c); err = -ENODEV;
kfree(ir); goto err_out_detach;
return -1;
} }
/* Phys addr can only be set after attaching (for ir->c.dev.bus_id) */ /* Phys addr can only be set after attaching (for ir->c.dev.bus_id) */
@ -389,15 +389,17 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
ir->c.dev.bus_id); ir->c.dev.bus_id);
/* init + register input device */ /* init + register input device */
ir_input_init(input_dev,&ir->ir,ir_type,ir->ir_codes); ir_input_init(input_dev, &ir->ir, ir_type, ir->ir_codes);
input_dev->id.bustype = BUS_I2C; input_dev->id.bustype = BUS_I2C;
input_dev->name = ir->c.name; input_dev->name = ir->c.name;
input_dev->phys = ir->phys; input_dev->phys = ir->phys;
/* register event device */ err = input_register_device(ir->input);
input_register_device(ir->input); if (err)
goto err_out_detach;
printk(DEVNAME ": %s detected at %s [%s]\n", printk(DEVNAME ": %s detected at %s [%s]\n",
ir->input->name,ir->input->phys,adap->name); ir->input->name, ir->input->phys, adap->name);
/* start polling via eventd */ /* start polling via eventd */
INIT_WORK(&ir->work, ir_work); INIT_WORK(&ir->work, ir_work);
@ -407,6 +409,13 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
schedule_work(&ir->work); schedule_work(&ir->work);
return 0; return 0;
err_out_detach:
i2c_detach_client(&ir->c);
err_out_free:
input_free_device(input_dev);
kfree(ir);
return err;
} }
static int ir_detach(struct i2c_client *client) static int ir_detach(struct i2c_client *client)
@ -414,7 +423,7 @@ static int ir_detach(struct i2c_client *client)
struct IR_i2c *ir = i2c_get_clientdata(client); struct IR_i2c *ir = i2c_get_clientdata(client);
/* kill outstanding polls */ /* kill outstanding polls */
del_timer(&ir->timer); del_timer_sync(&ir->timer);
flush_scheduled_work(); flush_scheduled_work();
/* unregister devices */ /* unregister devices */

View File

@ -131,6 +131,23 @@ static void saa7134_input_timer(unsigned long data)
mod_timer(&ir->timer, timeout); mod_timer(&ir->timer, timeout);
} }
static void saa7134_ir_start(struct saa7134_dev *dev, struct saa7134_ir *ir)
{
if (ir->polling) {
init_timer(&ir->timer);
ir->timer.function = saa7134_input_timer;
ir->timer.data = (unsigned long)dev;
ir->timer.expires = jiffies + HZ;
add_timer(&ir->timer);
}
}
static void saa7134_ir_stop(struct saa7134_dev *dev)
{
if (dev->remote->polling)
del_timer_sync(&dev->remote->timer);
}
int saa7134_input_init1(struct saa7134_dev *dev) int saa7134_input_init1(struct saa7134_dev *dev)
{ {
struct saa7134_ir *ir; struct saa7134_ir *ir;
@ -141,6 +158,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
u32 mask_keyup = 0; u32 mask_keyup = 0;
int polling = 0; int polling = 0;
int ir_type = IR_TYPE_OTHER; int ir_type = IR_TYPE_OTHER;
int err;
if (dev->has_remote != SAA7134_REMOTE_GPIO) if (dev->has_remote != SAA7134_REMOTE_GPIO)
return -ENODEV; return -ENODEV;
@ -267,9 +285,8 @@ int saa7134_input_init1(struct saa7134_dev *dev)
ir = kzalloc(sizeof(*ir), GFP_KERNEL); ir = kzalloc(sizeof(*ir), GFP_KERNEL);
input_dev = input_allocate_device(); input_dev = input_allocate_device();
if (!ir || !input_dev) { if (!ir || !input_dev) {
kfree(ir); err = -ENOMEM;
input_free_device(input_dev); goto err_out_free;
return -ENOMEM;
} }
ir->dev = input_dev; ir->dev = input_dev;
@ -300,18 +317,22 @@ int saa7134_input_init1(struct saa7134_dev *dev)
} }
input_dev->cdev.dev = &dev->pci->dev; input_dev->cdev.dev = &dev->pci->dev;
/* all done */
dev->remote = ir; dev->remote = ir;
if (ir->polling) { saa7134_ir_start(dev, ir);
init_timer(&ir->timer);
ir->timer.function = saa7134_input_timer; err = input_register_device(ir->dev);
ir->timer.data = (unsigned long)dev; if (err)
ir->timer.expires = jiffies + HZ; goto err_out_stop;
add_timer(&ir->timer);
}
input_register_device(ir->dev);
return 0; return 0;
err_out_stop:
saa7134_ir_stop(dev);
dev->remote = NULL;
err_out_free:
input_free_device(input_dev);
kfree(ir);
return err;
} }
void saa7134_input_fini(struct saa7134_dev *dev) void saa7134_input_fini(struct saa7134_dev *dev)
@ -319,8 +340,7 @@ void saa7134_input_fini(struct saa7134_dev *dev)
if (NULL == dev->remote) if (NULL == dev->remote)
return; return;
if (dev->remote->polling) saa7134_ir_stop(dev);
del_timer_sync(&dev->remote->timer);
input_unregister_device(dev->remote->dev); input_unregister_device(dev->remote->dev);
kfree(dev->remote); kfree(dev->remote);
dev->remote = NULL; dev->remote = NULL;

View File

@ -86,6 +86,7 @@ MODULE_DEVICE_TABLE(usb, qcm_table);
static void qcm_register_input(struct qcm *cam, struct usb_device *dev) static void qcm_register_input(struct qcm *cam, struct usb_device *dev)
{ {
struct input_dev *input_dev; struct input_dev *input_dev;
int error;
usb_make_path(dev, cam->input_physname, sizeof(cam->input_physname)); usb_make_path(dev, cam->input_physname, sizeof(cam->input_physname));
strncat(cam->input_physname, "/input0", sizeof(cam->input_physname)); strncat(cam->input_physname, "/input0", sizeof(cam->input_physname));
@ -106,7 +107,13 @@ static void qcm_register_input(struct qcm *cam, struct usb_device *dev)
input_dev->private = cam; input_dev->private = cam;
input_register_device(cam->input); error = input_register_device(cam->input);
if (error) {
warn("Failed to register camera's input device, err: %d\n",
error);
input_free_device(cam->input);
cam->input = NULL;
}
} }
static void qcm_unregister_input(struct qcm *cam) static void qcm_unregister_input(struct qcm *cam)