Skip to content

Commit

Permalink
[media] staging: as102: Initial import from Abilis
Browse files Browse the repository at this point in the history
Changes by Devin Heitmueller:

Import the original Abilis Systems as102 driver.  The source is unmodified,
with the only changes I've made so far were that I created a Kconfig and
Makefile so that the code builds in a standard v4l-dvb tree.

This driver requires firmware (which Abilis has provided with redistribution
terms which will allow it to be bundled in the Linux distributions).   The
firmware can be downloaded from here:

Thanks to Rainer Miethling from PCTV Systems for working to get the driver
released (for use with the PCTV 74e) and Pierrick Hascoet from Abilis for
authoring the driver.

Changes by Piotr Chmura:
 - moved the driver from media/dvb to staging/media
 - removed Makefile/Kconfig - compilation fails in current tree

[snjw23@gmail.com: edited changelog]
Signed-off-by: Pierrick Hascoet <pierrick.hascoet@abilis.com>
Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com>
Signed-off-by: Piotr Chmura <chmooreck@poczta.onet.pl>
Signed-off-by: Sylwester Nawrocki <snjw23@gmail.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
  • Loading branch information
Pierrick Hascoet authored and Mauro Carvalho Chehab committed Nov 3, 2011
1 parent 539b469 commit 41b44e0
Show file tree
Hide file tree
Showing 15 changed files with 3,694 additions and 0 deletions.
7 changes: 7 additions & 0 deletions drivers/staging/media/as102/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
config DVB_AS102
tristate "Abilis AS102 DVB receiver"
depends on DVB_CORE && USB && I2C && INPUT
help
Choose Y or M here if you have a device containing an AS102

To compile this driver as a module, choose M here
5 changes: 5 additions & 0 deletions drivers/staging/media/as102/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
dvb-as102-objs := as102_drv.o as102_fw.o as10x_cmd.o as10x_cmd_stream.o as102_fe.o as102_usb_drv.o as10x_cmd_cfg.o

obj-$(CONFIG_DVB_AS102) += dvb-as102.o

EXTRA_CFLAGS += -DLINUX -DCONFIG_AS102_USB -Idrivers/media/dvb/dvb-core
356 changes: 356 additions & 0 deletions drivers/staging/media/as102/as102_drv.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,356 @@
/*
* Abilis Systems Single DVB-T Receiver
* Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.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, 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/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/kref.h>
#include <asm/uaccess.h>
#include <linux/usb.h>

/* header file for Usb device driver*/
#include "as102_drv.h"
#include "as102_fw.h"

#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE)
#include "dvbdev.h"
#else
#warning >>> DVB_CORE not defined !!! <<<
#endif

int debug = 0;
module_param_named(debug, debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off debugging (default: off)");

int dual_tuner = 0;
module_param_named(dual_tuner, dual_tuner, int, 0644);
MODULE_PARM_DESC(dual_tuner, "Activate Dual-Tuner configuration (default: off)");

static int fw_upload = 1;
module_param_named(fw_upload, fw_upload, int, 0644);
MODULE_PARM_DESC(fw_upload, "Turn on/off default FW upload (default: on)");

static int pid_filtering = 0;
module_param_named(pid_filtering, pid_filtering, int, 0644);
MODULE_PARM_DESC(pid_filtering, "Activate HW PID filtering (default: off)");

static int ts_auto_disable = 0;
module_param_named(ts_auto_disable, ts_auto_disable, int, 0644);
MODULE_PARM_DESC(ts_auto_disable, "Stream Auto Enable on FW (default: off)");

int elna_enable = 1;
module_param_named(elna_enable, elna_enable, int, 0644);
MODULE_PARM_DESC(elna_enable, "Activate eLNA (default: on)");

#ifdef DVB_DEFINE_MOD_OPT_ADAPTER_NR
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
#endif

#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE)
static void as102_stop_stream(struct as102_dev_t *dev) {
struct as102_bus_adapter_t *bus_adap;

if (dev != NULL)
bus_adap = &dev->bus_adap;
else
return;

if (bus_adap->ops->stop_stream != NULL)
bus_adap->ops->stop_stream(dev);

if (ts_auto_disable) {
if (mutex_lock_interruptible(&dev->bus_adap.lock))
return;

if (as10x_cmd_stop_streaming(bus_adap) < 0) {
dprintk(debug, "as10x_cmd_stop_streaming failed\n");
}

mutex_unlock(&dev->bus_adap.lock);
}
}

static int as102_start_stream(struct as102_dev_t *dev) {

struct as102_bus_adapter_t *bus_adap;
int ret = -EFAULT;

if (dev != NULL)
bus_adap = &dev->bus_adap;
else
return ret;

if (bus_adap->ops->start_stream != NULL) {
ret = bus_adap->ops->start_stream(dev);
}

if (ts_auto_disable) {
if (mutex_lock_interruptible(&dev->bus_adap.lock))
return -EFAULT;

ret = as10x_cmd_start_streaming(bus_adap);

mutex_unlock(&dev->bus_adap.lock);
}

return ret;
}

static int as10x_pid_filter(struct as102_dev_t *dev,
int index, u16 pid, int onoff) {

struct as102_bus_adapter_t *bus_adap = &dev->bus_adap;
int ret = -EFAULT;

ENTER();

if (mutex_lock_interruptible(&dev->bus_adap.lock)) {
dprintk(debug, "mutex_lock_interruptible(lock) failed !\n");
return -EBUSY;
}

switch(onoff) {
case 0:
ret = as10x_cmd_del_PID_filter(bus_adap, (uint16_t) pid);
dprintk(debug, "DEL_PID_FILTER([%02d] 0x%04x) ret = %d\n",
index, pid, ret);
break;
case 1:
{
struct as10x_ts_filter filter;

filter.type = TS_PID_TYPE_TS;
filter.idx = 0xFF;
filter.pid = pid;

ret = as10x_cmd_add_PID_filter(bus_adap, &filter);
dprintk(debug, "ADD_PID_FILTER([%02d -> %02d], 0x%04x) ret = %d\n",
index, filter.idx, filter.pid, ret);
break;
}
}

mutex_unlock(&dev->bus_adap.lock);

LEAVE();
return ret;
}

static int as102_dvb_dmx_start_feed(struct dvb_demux_feed *dvbdmxfeed) {
int ret = 0;
struct dvb_demux *demux = dvbdmxfeed->demux;
struct as102_dev_t *as102_dev = demux->priv;

ENTER();

if (mutex_lock_interruptible(&as102_dev->sem))
return -ERESTARTSYS;

if (pid_filtering) {
as10x_pid_filter(as102_dev,
dvbdmxfeed->index, dvbdmxfeed->pid, 1);
}

if (as102_dev->streaming++ == 0) {
ret = as102_start_stream(as102_dev);
}

mutex_unlock(&as102_dev->sem);
LEAVE();
return ret;
}

static int as102_dvb_dmx_stop_feed(struct dvb_demux_feed *dvbdmxfeed) {
struct dvb_demux *demux = dvbdmxfeed->demux;
struct as102_dev_t *as102_dev = demux->priv;

ENTER();

if (mutex_lock_interruptible(&as102_dev->sem))
return -ERESTARTSYS;

if (--as102_dev->streaming == 0) {
as102_stop_stream(as102_dev);
}

if (pid_filtering) {
as10x_pid_filter(as102_dev,
dvbdmxfeed->index, dvbdmxfeed->pid, 0);
}

mutex_unlock(&as102_dev->sem);
LEAVE();
return 0;
}
#endif

int as102_dvb_register(struct as102_dev_t *as102_dev) {
int ret = 0;
ENTER();

#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE)
ret = dvb_register_adapter(&as102_dev->dvb_adap,
DEVICE_FULL_NAME,
THIS_MODULE,
#if defined(CONFIG_AS102_USB)
&as102_dev->bus_adap.usb_dev->dev
#elif defined(CONFIG_AS102_SPI)
&as102_dev->bus_adap.spi_dev->dev
#else
#error >>> dvb_register_adapter <<<
#endif
#ifdef DVB_DEFINE_MOD_OPT_ADAPTER_NR
, adapter_nr
#endif
);
if (ret < 0) {
err("%s: dvb_register_adapter() failed (errno = %d)",
__FUNCTION__, ret);
goto failed;
}

as102_dev->dvb_dmx.priv = as102_dev;
as102_dev->dvb_dmx.filternum = pid_filtering ? 16 : 256;
as102_dev->dvb_dmx.feednum = 256;
as102_dev->dvb_dmx.start_feed = as102_dvb_dmx_start_feed;
as102_dev->dvb_dmx.stop_feed = as102_dvb_dmx_stop_feed;

as102_dev->dvb_dmx.dmx.capabilities = DMX_TS_FILTERING |
DMX_SECTION_FILTERING;

as102_dev->dvb_dmxdev.filternum = as102_dev->dvb_dmx.filternum;
as102_dev->dvb_dmxdev.demux = &as102_dev->dvb_dmx.dmx;
as102_dev->dvb_dmxdev.capabilities = 0;

if ((ret = dvb_dmx_init(&as102_dev->dvb_dmx)) < 0) {
err("%s: dvb_dmx_init() failed (errno = %d)",
__FUNCTION__, ret);
goto failed;
}

ret = dvb_dmxdev_init(&as102_dev->dvb_dmxdev, &as102_dev->dvb_adap);
if (ret < 0) {
err("%s: dvb_dmxdev_init() failed (errno = %d)",
__FUNCTION__, ret);
goto failed;
}

ret = as102_dvb_register_fe(as102_dev, &as102_dev->dvb_fe);
if (ret < 0) {
err("%s: as102_dvb_register_frontend() failed (errno = %d)",
__FUNCTION__, ret);
goto failed;
}
#endif

/* init bus mutex for token locking */
mutex_init(&as102_dev->bus_adap.lock);

/* init start / stop stream mutex */
mutex_init(&as102_dev->sem);

#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)
/*
* try to load as102 firmware. If firmware upload failed, we'll be
* able to upload it later.
*/
if (fw_upload)
try_then_request_module(as102_fw_upload(&as102_dev->bus_adap),
"firmware_class");
#endif

failed:
LEAVE();
/* FIXME: free dvb_XXX */
return ret;
}

void as102_dvb_unregister(struct as102_dev_t *as102_dev) {
ENTER();

#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE)
/* unregister as102 frontend */
as102_dvb_unregister_fe(&as102_dev->dvb_fe);

/* unregister demux device */
dvb_dmxdev_release(&as102_dev->dvb_dmxdev);
dvb_dmx_release(&as102_dev->dvb_dmx);

/* unregister dvb adapter */
dvb_unregister_adapter(&as102_dev->dvb_adap);
#endif
LEAVE();
}

static int __init as102_driver_init(void) {
int ret = 0;

ENTER();

/* register this driver with the low level subsystem */
#if defined(CONFIG_AS102_USB)
ret = usb_register(&as102_usb_driver);
if (ret)
err("usb_register failed (ret = %d)", ret);
#endif
#if defined(CONFIG_AS102_SPI)
ret = spi_register_driver(&as102_spi_driver);
if (ret)
printk(KERN_ERR "spi_register failed (ret = %d)", ret);
#endif

LEAVE();
return ret;
}

/*
* Mandatory function : Adds a special section to the module indicating
* where initialisation function is defined
*/
module_init(as102_driver_init);

/**
* \brief as102 driver exit point. This function is called when device has
* to be removed.
*/
static void __exit as102_driver_exit(void) {
ENTER();
/* deregister this driver with the low level bus subsystem */
#if defined(CONFIG_AS102_USB)
usb_deregister(&as102_usb_driver);
#endif
#if defined(CONFIG_AS102_SPI)
spi_unregister_driver(&as102_spi_driver);
#endif
LEAVE();
}

/*
* required function for unload: Adds a special section to the module
* indicating where unload function is defined
*/
module_exit(as102_driver_exit);
/* modinfo details */
MODULE_DESCRIPTION(DRIVER_FULL_NAME);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Pierrick Hascoet <pierrick.hascoet@abilis.com>");

/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */
Loading

0 comments on commit 41b44e0

Please sign in to comment.