--- v4l-dvb/linux/drivers/media/dvb/dvb-usb/dvb-usb-remote.c.orig +++ v4l-dvb/linux/drivers/media/dvb/dvb-usb/dvb-usb-remote.c @@ -12,6 +12,112 @@ #include #endif +/* webcamd svn currently only supports raw lirc devices */ +#define FORCE_LIRC_RAW + +#ifdef FORCE_LIRC_RAW +#define MODULE_NAME "dvb-usb-remote" +#include + +struct dvb_usb_IR { + struct dvb_usb_device *dev; + struct input_dev *input; + char name[32]; + char phys[32]; + + /* poll external decoder */ + int polling; + struct delayed_work work; + u32 lastevent; + + /* IR device properties */ + struct ir_dev_props props; +}; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) +static void dvb_usb_ir_work(void *data) +#else +static void dvb_usb_ir_work(struct work_struct *work) +#endif +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) + struct dvb_usb_IR *ir = data; +#else + struct dvb_usb_IR *ir = container_of(work, struct dvb_usb_IR, work.work); +#endif + + u32 event; + int state; + struct ir_raw_event ev; + + /* TODO: need a lock here. We can simply skip checking for the remote control + if we're busy. */ + + /* when the parameter has been set to 1 via sysfs while the driver was running */ + if (dvb_usb_disable_rc_polling) + return; + + if (ir->dev->props.rc_query(ir->dev,&event,&state)) { + err("error while querying for an remote control event."); + goto schedule; + } + + + switch (state) { + case REMOTE_NO_KEY_PRESSED: + if (!ir->lastevent) + break; + ev.pulse = false; + ev.duration = 100; + ir_raw_event_store(ir->input, &ev); + ir_raw_event_reset(ir->input); + ir->lastevent = 0; + break; + case REMOTE_KEY_PRESSED: + deb_rc("key pressed\n"); + case REMOTE_KEY_REPEAT: + deb_rc("key repeated\n"); +#if 1 + printf("lirc event 0x%lx\n", (long)event); +#endif + if (event < 1000) + event *= 1000; + ir_raw_event_reset(ir->input); + ev.duration = event; + ev.pulse = true; + ir_raw_event_store(ir->input, &ev); + ir->lastevent = event; + break; + default: + break; + } + +schedule: + schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling)); +} + +static int dvb_usb_ir_start(void *priv) +{ + struct dvb_usb_IR *ir = priv; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) + INIT_DELAYED_WORK(&ir->work, dvb_usb_ir_work, ir); +#else + INIT_DELAYED_WORK(&ir->work, dvb_usb_ir_work); +#endif + schedule_delayed_work(&ir->work, 0); + + return 0; +} + +static void dvb_usb_ir_stop(void *priv) +{ + struct dvb_usb_IR *ir = priv; + + cancel_delayed_work_sync(&ir->work); +} +#endif + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) static int dvb_usb_getkeycode(struct input_dev *dev, int scancode, int *keycode) @@ -79,6 +185,7 @@ static int dvb_usb_setkeycode(struct inp } #endif +#ifndef FORCE_LIRC_RAW /* Remote-control poll function - called every dib->rc_query_interval ms to see * whether the remote control has received anything. * @@ -167,18 +274,80 @@ static void dvb_usb_read_remote_control( schedule: schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc_interval)); } +#endif int dvb_usb_remote_init(struct dvb_usb_device *d) { struct input_dev *input_dev; int i; int err; +#ifdef FORCE_LIRC_RAW + struct dvb_usb_IR *ir; +#endif if (d->props.rc_key_map == NULL || d->props.rc_query == NULL || dvb_usb_disable_rc_polling) return 0; +#ifdef FORCE_LIRC_RAW + ir = kzalloc(sizeof(*ir), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!ir || !input_dev) + goto err_out_free; + + /* record handles to ourself */ + ir->dev = d; + + ir->input = input_dev; + + ir->props.allowed_protos = IR_TYPE_LIRC; + ir->props.priv = ir; +#if 0 /* XXX never gets called */ + ir->props.open = dvb_usb_ir_start; + ir->props.close = dvb_usb_ir_stop; +#endif + ir->props.driver_type = RC_DRIVER_IR_RAW; + + /* This is how often we ask the chip for IR information */ + ir->polling = 100; /* ms */ + + ir->lastevent = 0; + + /* init input device */ + snprintf(ir->name, sizeof(ir->name), "USB DVB IR"); + + usb_make_path(d->udev, ir->phys, sizeof(ir->phys)); + strlcat(ir->phys, "/input0", sizeof(ir->phys)); + + input_dev->name = ir->name; + input_dev->phys = ir->phys; + input_dev->id.bustype = BUS_USB; + input_dev->id.version = 1; + input_dev->id.vendor = le16_to_cpu(d->udev->descriptor.idVendor); + input_dev->id.product = le16_to_cpu(d->udev->descriptor.idProduct); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) + input_dev->dev.parent = &d->udev->dev; +#else + input_dev->cdev.dev = &d->udev->dev; +#endif + + + /* all done */ + err = ir_input_register(ir->input, RC_MAP_RC5_TV /*RC_MAP_EMPTY*/, + &ir->props, MODULE_NAME); + if (err) + goto err_out_free; + +#if 1 /* XXX */ + dvb_usb_ir_start(ir); +#endif + return 0; + err_out_free: + kfree(ir); + return err; +#else usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys)); @@ -237,6 +406,7 @@ int dvb_usb_remote_init(struct dvb_usb_d d->state |= DVB_USB_STATE_REMOTE; +#endif return 0; }