Andy Walls | 24 Feb 05:38 2010
Picon

[PATCH v1] dvb_dummy_adapter

This patch implements a dvb_dummy_adapter module capable of creating up
to DVB_MAX_ADAPTERS software DVB adapters.  It's probably not much good
except for testing applications.  It works with femon.  I have not
tested writing to the dvr0 device and reading back yet.

One can instantiate adapeters with different dummy frontends:

# modprobe dvb_dummy_adapter debug=1 fe_type=0,1,2,1

Will yield 4 adapters with dummy DVB-C, DVB-T, DVB-S, and DVB-T
frontends.

Since I stole a good bit of this from the dvb portion of the cx18
driver, I suspect I have too many items set up the device
initialization.

Comments welcome.

Signed-off-by: Andy Walls <awalls <at> radix.net>

diff -r 9d3b80c9f15a linux/drivers/media/dvb/Kconfig
--- a/linux/drivers/media/dvb/Kconfig	Thu Feb 18 20:56:08 2010 -0200
+++ b/linux/drivers/media/dvb/Kconfig	Tue Feb 23 23:21:23 2010 -0500
 <at>  <at>  -80,6 +80,10  <at>  <at> 
 	depends on DVB_CORE && PCI && I2C
 	source "drivers/media/dvb/ngene/Kconfig"

+comment "Supported Dummy DVB Adapters"
+	depends on DVB_CORE
+	source "drivers/media/dvb/dummy/Kconfig"
+
 comment "Supported DVB Frontends"
 	depends on DVB_CORE
 source "drivers/media/dvb/frontends/Kconfig"
diff -r 9d3b80c9f15a linux/drivers/media/dvb/Makefile
--- a/linux/drivers/media/dvb/Makefile	Thu Feb 18 20:56:08 2010 -0200
+++ b/linux/drivers/media/dvb/Makefile	Tue Feb 23 23:21:23 2010 -0500
 <at>  <at>  -15,6 +15,7  <at>  <at> 
 		dm1105/		\
 		pt1/		\
 		mantis/		\
-		ngene/
+		ngene/		\
+		dummy/

 obj-$(CONFIG_DVB_FIREDTV)	+= firewire/
diff -r 9d3b80c9f15a linux/drivers/media/dvb/dummy/Kconfig
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/linux/drivers/media/dvb/dummy/Kconfig	Tue Feb 23 23:21:23 2010 -0500
 <at>  <at>  -0,0 +1,10  <at>  <at> 
+config DVB_DUMMY_ADAPTER
+	tristate "Dummy DVB adapter driver"
+	depends on DVB_CORE
+	select DVB_DUMMY_FE if !DVB_FE_CUSTOMISE
+	default n
+	help
+	  A software only dummy DVB adapter driver.  Possibly useful for
+	  application test and development without using actual DVB hardware.
+
+	  Most people will want to say N for this driver.
diff -r 9d3b80c9f15a linux/drivers/media/dvb/dummy/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/linux/drivers/media/dvb/dummy/Makefile	Tue Feb 23 23:21:23 2010 -0500
 <at>  <at>  -0,0 +1,3  <at>  <at> 
+obj-$(CONFIG_DVB_DUMMY_ADAPTER) += dvb_dummy_adapter.o
+
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff -r 9d3b80c9f15a linux/drivers/media/dvb/dummy/dvb_dummy_adapter.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/linux/drivers/media/dvb/dummy/dvb_dummy_adapter.c	Tue Feb 23 23:21:23 2010 -0500
 <at>  <at>  -0,0 +1,364  <at>  <at> 
+/*
+ *  Dummy DVB adapter driver
+ *
+ *  Copyright (C) 2010 Andy Walls <awalls <at> radix.net>
+ *
+ *  Partially based on cx18-dvb.c driver code
+ *  Copyright (C) 2008 Steve Toth <stoth <at> kernellabs.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+
+#include <linux/platform_device.h>
+
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+#include "dvbdev.h"
+#include "dmxdev.h"
+#include "dvb_dummy_fe.h"
+
+MODULE_AUTHOR("Andy Walls");
+MODULE_DESCRIPTION("Dummy DVB adapter driver");
+MODULE_LICENSE("GPL");
+#define DVB_DUMMY_VERSION "0:0.1"
+MODULE_VERSION(DVB_DUMMY_VERSION);
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int debug;
+
+static int fe_type[DVB_MAX_ADAPTERS];
+static unsigned int fe_type_c = 1;
+
+module_param(debug, int, 0644);
+module_param_array(fe_type, int, &fe_type_c, 0644);
+
+MODULE_PARM_DESC(debug, "Debug level. Default: 0");
+MODULE_PARM_DESC(fe_type, "Frontend type\n"
+			  "\t\t\t0: DVB-C\n"
+			  "\t\t\t1: DVB-T\n"
+			  "\t\t\t2: DVB-S\n"
+			  "\t\t\tDefault: 0: DVB-C");
+
+struct dvb_dummy {
+	struct platform_device *plat_dev;
+	int instance;
+
+	struct dmx_frontend hw_frontend;
+	struct dmx_frontend mem_frontend;
+	struct dmxdev dmxdev;
+	struct dvb_adapter dvb_adapter;
+	struct dvb_demux demux;
+	struct dvb_frontend *fe;
+	struct dvb_net dvbnet;
+
+	int feeding;
+	struct mutex feedlock; /* protects feeding variable */
+};
+
+static int dvb_dummy_start_feed(struct dvb_demux_feed *feed)
+{
+	struct dvb_demux *demux = feed->demux;
+	struct dvb_dummy *dummy = (struct dvb_dummy *) demux->priv;
+
+	if (dummy == NULL)
+		return -EINVAL;
+
+	if (debug)
+		printk(KERN_INFO "dvb_dummy_adapter%d: "
+		       "Start feed: pid = 0x%x index = %d\n",
+		       dummy->instance, feed->pid, feed->index);
+
+	if (!demux->dmx.frontend)
+		return -EINVAL;
+
+	mutex_lock(&dummy->feedlock);
+	if (dummy->feeding++ == 0 && debug)
+		printk(KERN_INFO
+		       "dvb_dummy_adapter%d: Starting transport\n",
+		       dummy->instance);
+	mutex_unlock(&dummy->feedlock);
+	return 0;
+}
+
+static int dvb_dummy_stop_feed(struct dvb_demux_feed *feed)
+{
+	struct dvb_demux *demux = feed->demux;
+	struct dvb_dummy *dummy = (struct dvb_dummy *) demux->priv;
+
+	if (dummy == NULL)
+		return -EINVAL;
+
+	if (debug)
+		printk(KERN_INFO "dvb_dummy_adapter%d: "
+		       "Stop feed: pid = 0x%x index = %d\n",
+		       dummy->instance, feed->pid, feed->index);
+
+	mutex_lock(&dummy->feedlock);
+	if (--dummy-≥feeding == 0 && debug)
+		printk(KERN_INFO
+		       "dvb_dummy_adapter%d: Stopping transport\n",
+		       dummy->instance);
+	mutex_unlock(&dummy->feedlock);
+
+	return 0;
+}
+
+static int __devinit dvb_dummy_register(struct dvb_dummy *dummy)
+{
+	struct dvb_adapter *dvb_adapter;
+	struct dvb_demux *dvbdemux;
+	struct dmx_demux *dmx;
+	int ret;
+
+	ret = dvb_register_adapter(&dummy->dvb_adapter, "dvb_dummy_adapter",
+				   THIS_MODULE, &dummy->plat_dev->dev,
+				   adapter_nr);
+	if (ret < 0)
+		goto err_out;
+
+	dvb_adapter = &dummy->dvb_adapter;
+
+	dvbdemux = &dummy->demux;
+
+	dvbdemux->priv = (void *) dummy;
+
+	dvbdemux->filternum = 256;
+	dvbdemux->feednum = 256;
+	dvbdemux->start_feed = dvb_dummy_start_feed;
+	dvbdemux->stop_feed = dvb_dummy_stop_feed;
+	dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
+		DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
+	ret = dvb_dmx_init(dvbdemux);
+	if (ret < 0)
+		goto err_dvb_unregister_adapter;
+
+	dmx = &dvbdemux->dmx;
+
+	dummy->hw_frontend.source = DMX_FRONTEND_0;
+	dummy->mem_frontend.source = DMX_MEMORY_FE;
+	dummy->dmxdev.filternum = 256;
+	dummy->dmxdev.demux = dmx;
+
+	ret = dvb_dmxdev_init(&dummy->dmxdev, dvb_adapter);
+	if (ret < 0)
+		goto err_dvb_dmx_release;
+
+	ret = dmx->add_frontend(dmx, &dummy->hw_frontend);
+	if (ret < 0)
+		goto err_dvb_dmxdev_release;
+
+	ret = dmx->add_frontend(dmx, &dummy->mem_frontend);
+	if (ret < 0)
+		goto err_remove_hw_frontend;
+
+	ret = dmx->connect_frontend(dmx, &dummy->hw_frontend);
+	if (ret < 0)
+		goto err_remove_mem_frontend;
+
+	switch (fe_type[dummy->instance]) {
+	case 1:
+		dummy->fe = dvb_attach(dvb_dummy_fe_ofdm_attach);
+		break;
+	case 2:
+		dummy->fe = dvb_attach(dvb_dummy_fe_qpsk_attach);
+		break;
+	default:
+		dummy->fe = dvb_attach(dvb_dummy_fe_qam_attach);
+		break;
+	}
+	ret = (dummy->fe == NULL) ? -1 : 0;
+	if (ret < 0)
+		goto err_disconnect_frontend;
+
+	ret = dvb_register_frontend(dvb_adapter, dummy->fe);
+	if (ret < 0)
+		goto err_release_frontend;
+
+	dvb_net_init(dvb_adapter, &dummy->dvbnet, dmx);
+
+	printk(KERN_INFO "dvb_dummy_adapter%d: DVB Frontend registered\n",
+	       dummy->instance);
+	printk(KERN_INFO "dvb_dummy_adapter%d: Registered DVB adapter%d\n",
+	       dummy->instance, dummy->dvb_adapter.num);
+
+	mutex_init(&dummy->feedlock);
+	return ret;
+
+err_release_frontend:
+	if (dummy->fe->ops.release)
+		dummy->fe->ops.release(dummy->fe);
+err_disconnect_frontend:
+	dmx->disconnect_frontend(dmx);
+err_remove_mem_frontend:
+	dmx->remove_frontend(dmx, &dummy->mem_frontend);
+err_remove_hw_frontend:
+	dmx->remove_frontend(dmx, &dummy->hw_frontend);
+err_dvb_dmxdev_release:
+	dvb_dmxdev_release(&dummy->dmxdev);
+err_dvb_dmx_release:
+	dvb_dmx_release(dvbdemux);
+err_dvb_unregister_adapter:
+	dvbdemux->priv = NULL;
+	dvb_unregister_adapter(dvb_adapter);
+err_out:
+	return ret;
+}
+
+static void dvb_dummy_unregister(struct dvb_dummy *dummy)
+{
+	struct dvb_adapter *dvb_adapter;
+	struct dvb_demux *dvbdemux;
+	struct dmx_demux *dmx;
+
+	printk(KERN_INFO "dvb_dummy_adapter%d: DVB Frontend unegister\n",
+	       dummy->instance);
+	printk(KERN_INFO "dvb_dummy_adapter%d: Unregister DVB adapter%d\n",
+	       dummy->instance, dummy->dvb_adapter.num);
+
+	dvb_adapter = &dummy->dvb_adapter;
+	dvbdemux = &dummy->demux;
+	dmx = &dvbdemux->dmx;
+
+	dmx->close(dmx);
+	dvb_net_release(&dummy->dvbnet);
+	dmx->remove_frontend(dmx, &dummy->mem_frontend);
+	dmx->remove_frontend(dmx, &dummy->hw_frontend);
+	dvb_dmxdev_release(&dummy->dmxdev);
+	dvb_dmx_release(dvbdemux);
+	dvbdemux->priv = NULL;
+	dvb_unregister_frontend(dummy->fe);
+	dvb_frontend_detach(dummy->fe);
+	dvb_unregister_adapter(dvb_adapter);
+}
+
+
+static int __devinit dvb_dummy_probe(struct platform_device *plat_dev)
+{
+	int ret;
+	struct dvb_dummy *dummy;
+
+	dummy = kzalloc(sizeof(struct dvb_dummy), GFP_KERNEL);
+	if (dummy == NULL) {
+		printk(KERN_ERR
+		       "dvb_dummy_adapter: out of memory for adapter %d\n",
+		       plat_dev->id);
+		return -ENOMEM;
+	}
+
+	dummy->plat_dev = plat_dev;
+	dummy->instance = plat_dev->id;
+
+	platform_set_drvdata(plat_dev, dummy);
+
+	ret = dvb_dummy_register(dummy);
+	if (ret < 0) {
+		platform_set_drvdata(plat_dev, NULL);
+		kfree(dummy);
+	}
+	return ret;
+}
+
+static int dvb_dummy_remove(struct platform_device *plat_dev)
+{
+	struct dvb_dummy *dummy;
+
+	dummy = platform_get_drvdata(plat_dev);
+	if (dummy == NULL)
+		return 0;
+
+	dvb_dummy_unregister(dummy);
+
+	platform_set_drvdata(plat_dev, NULL);
+	kfree(dummy);
+	return 0;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
+static struct platform_device_id dvb_dummy_platform_id_table[] = {
+	{ "dvb_dummy_adapter", 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(platform, dvb_dummy_platform_id_table);
+#endif
+
+static struct platform_driver dvb_dummy_platform_driver = {
+	.probe = dvb_dummy_probe,
+	.remove = dvb_dummy_remove,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
+	.id_table = dvb_dummy_platform_id_table,
+#endif
+	.driver = {
+		.name = "dvb_dummy_adapter",
+	},
+};
+
+static int __init dvb_dummy_init(void)
+{
+	int ret = 0;
+	int i, n;
+	struct platform_device *plat_dev;
+
+	printk(KERN_INFO
+	       "dvb_dummy_adapter: Begin initialization, version %s\n",
+	       DVB_DUMMY_VERSION);
+
+	n = fe_type_c;
+	if (n < 1 || n >= DVB_MAX_ADAPTERS) {
+		printk(KERN_ERR "dvb_dummy_adapter: "
+		       "Illegal number (%d) of frontend types specified\n", n);
+		ret = -EINVAL;
+		goto init_exit;
+	}
+
+	ret = platform_driver_register(&dvb_dummy_platform_driver);
+	if (ret) {
+		printk(KERN_ERR "dvb_dummy_adapter: "
+		       "Error %d from platform_driver_register()\n", ret);
+		goto init_exit;
+	}
+
+	for (i = 0; i < n; i++) {
+		plat_dev = platform_device_register_simple("dvb_dummy_adapter",
+							   i, NULL, 0);
+		if (IS_ERR(plat_dev)) {
+			printk(KERN_ERR "dvb_dummy_adapter: could not allocate"
+			       "and register instance %d\n", i);
+			ret = (i == 0) ? -ENODEV : 0;
+			break;
+		}
+	}
+
+init_exit:
+	printk(KERN_INFO "dvb_dummy_adapter: End initialization\n");
+	return ret;
+}
+
+static void __exit dvb_dummy_exit(void)
+{
+	printk(KERN_INFO "dvb_dummy_adapter: Begin exit\n");
+	platform_driver_unregister(&dvb_dummy_platform_driver);
+	printk(KERN_INFO "dvb_dummy_adapter: End exit\n");
+}
+
+module_init(dvb_dummy_init);
+module_exit(dvb_dummy_exit);


Gmane