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@xxxxxxxxx> 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 @@ -80,6 +80,10 @@ 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 @@ -15,6 +15,7 @@ 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 @@ -0,0 +1,10 @@ +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 @@ -0,0 +1,3 @@ +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 @@ -0,0 +1,364 @@ +/* + * Dummy DVB adapter driver + * + * Copyright (C) 2010 Andy Walls <awalls@xxxxxxxxx> + * + * Partially based on cx18-dvb.c driver code + * Copyright (C) 2008 Steve Toth <stoth@xxxxxxxxxxxxxx> + * + * 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); -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html