Created
September 30, 2019 08:51
-
-
Save maxlapshin/99c01ab4cf4e48d76819f4a96f6b8a90 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Dummy DVB adapter driver | |
* | |
* Copyright (C) 2010 Andy Walls <[email protected]> | |
* | |
* Partially based on cx18-dvb.c driver code | |
* Copyright (C) 2008 Steve Toth <[email protected]> | |
* | |
* 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=1; | |
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: 1"); | |
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: 2: DVB-S"); | |
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 __init 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 dvb_dummy_probe(struct platform_device *plat_dev) | |
{ | |
int ret; | |
struct dvb_dummy *dummy; | |
printk(KERN_INFO "probe %s %d\n", plat_dev->name, plat_dev->id); | |
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; | |
printk(KERN_INFO "unloading DVB device %d\n", plat_dev->id); | |
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; | |
n = fe_type_c; | |
printk(KERN_INFO | |
"dvb_dummy_adapter: Begin initialization, version %s, frontends: %d\n", | |
DVB_DUMMY_VERSION, n); | |
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; | |
} | |
void 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); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment