--- ../v4l-dvb/linux/drivers/media/IR/ir-lirc-codec.c.orig +++ ../v4l-dvb/linux/drivers/media/IR/ir-lirc-codec.c @@ -104,7 +104,7 @@ static int ir_lirc_ioctl(struct inode *n struct ir_input_dev *ir_dev; int ret = 0; void *drv_data; - unsigned long val; + __u32 val; lirc = lirc_get_pdata(filep); if (!lirc) @@ -118,7 +118,7 @@ static int ir_lirc_ioctl(struct inode *n switch (cmd) { case LIRC_SET_TRANSMITTER_MASK: - ret = get_user(val, (unsigned long *)arg); + ret = get_user(val, (__u32 *)arg); if (ret) return ret; @@ -129,7 +129,7 @@ static int ir_lirc_ioctl(struct inode *n break; case LIRC_SET_SEND_CARRIER: - ret = get_user(val, (unsigned long *)arg); + ret = get_user(val, (__u32 *)arg); if (ret) return ret; @@ -141,11 +141,11 @@ static int ir_lirc_ioctl(struct inode *n case LIRC_GET_SEND_MODE: val = LIRC_CAN_SEND_PULSE & LIRC_CAN_SEND_MASK; - ret = put_user(val, (unsigned long *)arg); + ret = put_user(val, (__u32 *)arg); break; case LIRC_SET_SEND_MODE: - ret = get_user(val, (unsigned long *)arg); + ret = get_user(val, (__u32 *)arg); if (ret) return ret; --- ../v4l-dvb/linux/drivers/media/IR/lirc_dev.c.orig +++ ../v4l-dvb/linux/drivers/media/IR/lirc_dev.c @@ -519,7 +519,7 @@ EXPORT_SYMBOL(lirc_dev_fop_poll); int lirc_dev_fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - unsigned long mode; + __u32 mode; int result = 0; struct irctl *ir = irctls[iminor(inode)]; @@ -536,7 +536,7 @@ int lirc_dev_fop_ioctl(struct inode *ino switch (cmd) { case LIRC_GET_FEATURES: - result = put_user(ir->d.features, (unsigned long *)arg); + result = put_user(ir->d.features, (__u32 *)arg); break; case LIRC_GET_REC_MODE: if (!(ir->d.features & LIRC_CAN_REC_MASK)) { @@ -546,7 +546,7 @@ int lirc_dev_fop_ioctl(struct inode *ino result = put_user(LIRC_REC2MODE (ir->d.features & LIRC_CAN_REC_MASK), - (unsigned long *)arg); + (__u32 *)arg); break; case LIRC_SET_REC_MODE: if (!(ir->d.features & LIRC_CAN_REC_MASK)) { @@ -554,7 +554,7 @@ int lirc_dev_fop_ioctl(struct inode *ino break; } - result = get_user(mode, (unsigned long *)arg); + result = get_user(mode, (__u32 *)arg); if (!result && !(LIRC_MODE2REC(mode) & ir->d.features)) result = -EINVAL; /* @@ -563,7 +563,7 @@ int lirc_dev_fop_ioctl(struct inode *ino */ break; case LIRC_GET_LENGTH: - result = put_user(ir->d.code_length, (unsigned long *)arg); + result = put_user(ir->d.code_length, (__u32 *)arg); break; case LIRC_GET_MIN_TIMEOUT: if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) || @@ -572,7 +572,7 @@ int lirc_dev_fop_ioctl(struct inode *ino break; } - result = put_user(ir->d.min_timeout, (unsigned long *)arg); + result = put_user(ir->d.min_timeout, (__u32 *)arg); break; case LIRC_GET_MAX_TIMEOUT: if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) || @@ -581,7 +581,7 @@ int lirc_dev_fop_ioctl(struct inode *ino break; } - result = put_user(ir->d.max_timeout, (unsigned long *)arg); + result = put_user(ir->d.max_timeout, (__u32 *)arg); break; default: result = -EINVAL; --- ../v4l-dvb/linux/drivers/media/IR/lirc_dev.h.orig +++ ../v4l-dvb/linux/drivers/media/IR/lirc_dev.h @@ -128,7 +128,7 @@ struct lirc_driver { unsigned long code_length; unsigned int buffer_size; /* in chunks holding one code each */ int sample_rate; - unsigned long features; + __u32 features; unsigned int chunk_size; --- ../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,172 @@ #include #endif +/* webcamd svn currently only supports raw lirc devices so emulate one */ +#define FORCE_LIRC_RAW +/* + * define LIRC_REMOTEPLUGIN to enable more hid-like behaviour + * that can be directly used by the (wip) FreeBSD port of the + * vdr remote plugin - this is not really correct since the + * Linux code reports /dev/lirc0 as a raw lirc device i.e. not + * one that reports decoded remote button events but raw ir pulse + * lengths. So if LIRC_REMOTEPLUGIN is undefined this now emulates + * rc5-like pulses instead that lirc can understand. + */ +/* #define LIRC_REMOTEPLUGIN */ + +#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; +#ifndef LIRC_REMOTEPLUGIN + int i, rc; +#endif + 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; +#ifdef LIRC_REMOTEPLUGIN + ev.pulse = false; + ev.duration = 100; + ir_raw_event_store(ir->input, &ev); + ir_raw_event_handle(ir->input); +#endif + ir->lastevent = 0; + break; + case REMOTE_KEY_REPEAT: + deb_rc("key repeated\n"); + case REMOTE_KEY_PRESSED: + deb_rc("key pressed\n"); +#if 1 + printf("lirc event 0x%lx\n", (long)event); +#endif +#ifndef LIRC_REMOTEPLUGIN + /* Emulate rc5-like pulses. */ + if (ir->lastevent) + ev.duration = 110000000; + else + ev.duration = 250000000; + ev.pulse = false; + ir_raw_event_store(ir->input, &ev); + rc = (event & ((1 << 11) - 1)) | (6 << 11); + for (i = 13; i--; rc = (rc << 1) & ((1 << 15) - 1)) { + switch ((rc >> 12) & 3) { + case 0: + ev.duration = 900 * 1000; + ev.pulse = false; + ir_raw_event_store(ir->input, &ev); + ev.pulse = true; + ir_raw_event_store(ir->input, &ev); + break; + case 1: + ev.duration = 1800 * 1000; + ev.pulse = false; + ir_raw_event_store(ir->input, &ev); + break; + case 2: + ev.duration = 1800 * 1000; + ev.pulse = true; + ir_raw_event_store(ir->input, &ev); + break; + case 3: + ev.duration = 900 * 1000; + ev.pulse = true; + ir_raw_event_store(ir->input, &ev); + ev.pulse = false; + ir_raw_event_store(ir->input, &ev); + break; + } + } + if ((rc >> 13) & 1) { + ev.duration = 900 * 1000; + ev.pulse = true; + ir_raw_event_store(ir->input, &ev); + } + ir_raw_event_handle(ir->input); +#else + if (event < 1000) + event *= 1000; + ev.duration = event; + ev.pulse = true; + ir_raw_event_store(ir->input, &ev); + ir_raw_event_handle(ir->input); +#endif + 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 +245,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 +334,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 +466,7 @@ int dvb_usb_remote_init(struct dvb_usb_d d->state |= DVB_USB_STATE_REMOTE; +#endif return 0; }