Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 41b44e04 authored by Pierrick Hascoet's avatar Pierrick Hascoet Committed by Mauro Carvalho Chehab
Browse files

[media] staging: as102: Initial import from Abilis



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: default avatarPierrick Hascoet <pierrick.hascoet@abilis.com>
Signed-off-by: default avatarDevin Heitmueller <dheitmueller@kernellabs.com>
Signed-off-by: default avatarPiotr Chmura <chmooreck@poczta.onet.pl>
Signed-off-by: default avatarSylwester Nawrocki <snjw23@gmail.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 539b4695
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
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 −0
Original line number Diff line number Diff line
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 −0
Original line number Diff line number Diff line
/*
 * 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: */
+146 −0
Original line number Diff line number Diff line
/*
 * 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.
 */

#if defined(CONFIG_AS102_USB)
#include <linux/usb.h>
extern struct usb_driver as102_usb_driver;
#endif

#if defined(CONFIG_AS102_SPI)
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/cdev.h>

extern struct spi_driver as102_spi_driver;
#endif

#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE)
#include "dvb_demux.h"
#include "dvb_frontend.h"
#include "dmxdev.h"
#endif

#define DRIVER_FULL_NAME "Abilis Systems as10x usb driver"
#define DRIVER_NAME "as10x_usb"

extern int debug;

#define dprintk(debug, args...) \
	do { if (debug) {	\
		printk(KERN_DEBUG "%s: ",__FUNCTION__);	\
		printk(args);	\
	} } while (0)

#ifdef TRACE
#define ENTER()                 printk(">> enter %s\n", __FUNCTION__)
#define LEAVE()                 printk("<< leave %s\n", __FUNCTION__)
#else
#define ENTER()
#define LEAVE()
#endif

#define AS102_DEVICE_MAJOR	192

#define AS102_USB_BUF_SIZE	512
#define MAX_STREAM_URB		32

#include "as10x_cmd.h"

#if defined(CONFIG_AS102_USB)
#include "as102_usb_drv.h"
#endif

#if defined(CONFIG_AS102_SPI)
#include "as10x_spi_drv.h"
#endif


struct as102_bus_adapter_t {
#if defined(CONFIG_AS102_USB)
	struct usb_device *usb_dev;
#elif defined(CONFIG_AS102_SPI)
	struct spi_device *spi_dev;
	struct cdev cdev; /* spidev raw device */

	struct timer_list timer;
	struct completion xfer_done;
#endif
	/* bus token lock */
	struct mutex lock;
	/* low level interface for bus adapter */
	union as10x_bus_token_t {
#if defined(CONFIG_AS102_USB)
		/* usb token */
		struct as10x_usb_token_cmd_t usb;
#endif
#if defined(CONFIG_AS102_SPI)
		/* spi token */
		struct as10x_spi_token_cmd_t spi;
#endif
	} token;

	/* token cmd xfer id */
	uint16_t cmd_xid;

	/* as10x command and response for dvb interface*/
	struct as10x_cmd_t *cmd, *rsp;

	/* bus adapter private ops callback */
	struct as102_priv_ops_t *ops;
};

struct as102_dev_t {
	struct as102_bus_adapter_t bus_adap;
	struct list_head device_entry;
	struct kref kref;
	unsigned long minor;

#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE)
	struct dvb_adapter dvb_adap;
	struct dvb_frontend dvb_fe;
	struct dvb_demux dvb_dmx;
	struct dmxdev dvb_dmxdev;
#endif

	/* demodulator stats */
	struct as10x_demod_stats demod_stats;
	/* signal strength */
	uint16_t signal_strength;
	/* bit error rate */
	uint32_t ber;

	/* timer handle to trig ts stream download */
	struct timer_list timer_handle;

	struct mutex sem;
	dma_addr_t dma_addr;
	void *stream;
	int streaming;
	struct urb *stream_urb[MAX_STREAM_URB];
};

int as102_dvb_register(struct as102_dev_t *dev);
void as102_dvb_unregister(struct as102_dev_t *dev);

#if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE)
int as102_dvb_register_fe(struct as102_dev_t *dev, struct dvb_frontend *fe);
int as102_dvb_unregister_fe(struct dvb_frontend *dev);
#endif

/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */
+647 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading