New dvb-s2 tuner, and a hack to get remaining remotes working

Juergen Lock nox at jelal.kn-bremen.de
Mon Jan 31 21:32:08 UTC 2011


The hack was to force dvb tuner remotes to /dev/lircX which webcamd
svn now supports:

	http://people.freebsd.org/~nox/dvb/webcamd/patch-remote1.txt

(also copied below) - I wasn't able to test this with the lirc
port yet (it complained that it can't set /dev/lirc0 to O_NONBLOCK),
but at least it seems to work when used as -h /dev/lirc0 with my
port of the vdr remote plugin, so vdr can now _finally_ use all the
remotes of the usb dvb tuners I have working here. :)

 The new tuner is a "TechnoTrend S2-3600 DVB-S2 USB" and it needs
a small patch that Hans already committed to webcamd svn:

	http://people.freebsd.org/~nox/dvb/webcamd/patch-pctv452e.c.txt

It is driven by pctv452e.c out of the liplianin repo like my other
dvb-s2 tuner and seems to work just as well, the advantage of
this one is that it a) has the most complete remote of all the
tuners I have here (the other one, the original PCTV 452e has the
most minimalistic remote of them all) and b) it seems to be more
readily available here than the PCTV 452e now, that one meanwhile
seems to have been replaced by a PCTV 460e for which there still
is no Linux driver...

 If you want to test webcamd svn see hps' page:

	http://www.selasky.org/hans_petter/video4bsd/

 To use it with the remote patch and vdr add this to vdr's args:

	'-Premote -h /dev/lirc0'

then when you start vdr and vdr-sxfe the on-screen-display (osd)
should ask you to configure the remote by pressing the buttons
you want to assign.  The vdr Call for testing post with further
notes is here:

	http://lists.freebsd.org/pipermail/freebsd-multimedia/2011-January/011554.html

and more links are here:

	http://people.freebsd.org/~nox/dvb/

 And now for the remote patch...

 Enjoy,
	Juergen

--- 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 <linux/usb_input.h>
 #endif
 
+/* webcamd svn currently only supports raw lirc devices */
+#define FORCE_LIRC_RAW
+
+#ifdef FORCE_LIRC_RAW
+#define MODULE_NAME "dvb-usb-remote"
+#include <media/ir-core.h>
+
+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;
 }
 


More information about the freebsd-multimedia mailing list