Commit 3169c9b2 authored by Michel Ludwig's avatar Michel Ludwig Committed by Mauro Carvalho Chehab

V4L/DVB (12788): tm6000: Add initial DVB-T support

Signed-off-by: default avatarMichel Ludwig <michel.ludwig@gmail.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent a4cf976c
tm6000-objs := tm6000-cards.o \ tm6000-objs := tm6000-cards.o \
tm6000-core.o \ tm6000-core.o \
tm6000-i2c.o \ tm6000-i2c.o \
tm6000-video.o tm6000-video.o \
tm6000-dvb.o \
hack.o \
obj-$(CONFIG_VIDEO_TM6000) += tm6000.o obj-$(CONFIG_VIDEO_TM6000) += tm6000.o
......
/*
hack.h - hackish code that needs to be improved (or removed) at a
later point
Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.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 version 2
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 "hack.h"
#include "tm6000.h"
#include <linux/usb.h>
static inline int tm6000_snd_control_msg(struct tm6000_core *dev, __u8 request, __u16 value, __u16 index, void *data, __u16 size)
{
return tm6000_read_write_usb (dev, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, request, value, index, data, size);
}
static int pseudo_zl10353_pll(struct tm6000_core *tm6000_dev, struct dvb_frontend_parameters *p)
{
int ret;
u8 *data = kzalloc(50*sizeof(u8), GFP_KERNEL);
printk(KERN_ALERT "should set frequency %u\n", p->frequency);
printk(KERN_ALERT "and bandwith %u\n", p->u.ofdm.bandwidth);
if(tm6000_dev->dvb->frontend->ops.tuner_ops.set_params) {
tm6000_dev->dvb->frontend->ops.tuner_ops.set_params(tm6000_dev->dvb->frontend, p);
}
else {
printk(KERN_ALERT "pseudo zl10353: couldn't set tuner parameters\n");
}
// init ZL10353
data[0] = 0x0b;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x501e, 0x00, data, 0x1);
msleep(15);
data[0] = 0x80;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x551e, 0x00, data, 0x1);
msleep(100);
data[0] = 0x01;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0xea1e, 0x00, data, 0x1);
msleep(100);
data[0] = 0x00;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0xea1e, 0x00, data, 0x1);
msleep(15);
data[0] = 0x1c;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x561e, 0x00, data, 0x1);
msleep(15);
data[0] = 0x40;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x5e1e, 0x00, data, 0x1);
msleep(15);
data[0] = 0x36;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x641e, 0x00, data, 0x1);
msleep(15);
data[0] = 0x67;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x651e, 0x00, data, 0x1);
msleep(15);
data[0] = 0xe5;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x661e, 0x00, data, 0x1);
msleep(15);
data[0] = 0x19;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x6c1e, 0x00, data, 0x1);
msleep(15);
data[0] = 0xe9;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x6d1e, 0x00, data, 0x1);
msleep(15);
data[0] = 0x44;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x511e, 0x00, data, 0x1);
msleep(15);
data[0] = 0x46;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x521e, 0x00, data, 0x1);
msleep(15);
data[0] = 0x15;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x531e, 0x00, data, 0x1);
msleep(15);
data[0] = 0x0f;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x541e, 0x00, data, 0x1);
msleep(15);
data[0] = 0x75;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x5c1e, 0x00, data, 0x1);
msleep(15);
data[0] = 0x01;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x701e, 0x00, data, 0x1);
msleep(15);
data[0] = 0x00;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x701e, 0x00, data, 0x1);
msleep(15);
msleep(50);
switch(p->u.ofdm.bandwidth) {
case BANDWIDTH_8_MHZ:
data[0] = 0x00;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x701e, 0x00, data, 0x1);
msleep(15);
data[0] = 0x36;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x641e, 0x00, data, 0x1);
msleep(15);
data[0] = 0x67;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x651e, 0x00, data, 0x1);
msleep(15);
data[0] = 0xe5;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x661e, 0x00, data, 0x1);
msleep(15);
data[0] = 0x19;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x6c1e, 0x00, data, 0x1);
msleep(15);
data[0] = 0xe9;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x6d1e, 0x00, data, 0x1);
msleep(15);
data[0] = 0x44;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x511e, 0x00, data, 0x1);
msleep(15);
data[0] = 0x46;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x521e, 0x00, data, 0x1);
msleep(15);
data[0] = 0x15;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x531e, 0x00, data, 0x1);
msleep(15);
data[0] = 0x0f;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x541e, 0x00, data, 0x1);
msleep(15);
data[0] = 0x75;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x5c1e, 0x00, data, 0x1);
msleep(15);
data[0] = 0x01;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x701e, 0x00, data, 0x1);
msleep(15);
break;
default:
printk(KERN_ALERT "tm6000: bandwidth not supported\n");
case BANDWIDTH_7_MHZ:
data[0] = 0x00;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x701e, 0x00, data, 0x1);
msleep(15);
data[0] = 0x35;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x641e, 0x00, data, 0x1);
msleep(15);
data[0] = 0x5a;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x651e, 0x00, data, 0x1);
msleep(15);
data[0] = 0xe9;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x661e, 0x00, data, 0x1);
msleep(15);
data[0] = 0x19;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x6c1e, 0x00, data, 0x1);
msleep(15);
data[0] = 0xe9;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x6d1e, 0x00, data, 0x1);
msleep(15);
data[0] = 0x44;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x511e, 0x00, data, 0x1);
msleep(15);
data[0] = 0x46;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x521e, 0x00, data, 0x1);
msleep(15);
data[0] = 0x15;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x531e, 0x00, data, 0x1);
msleep(15);
data[0] = 0x0f;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x541e, 0x00, data, 0x1);
msleep(15);
data[0] = 0x86;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x5c1e, 0x00, data, 0x1);
msleep(15);
data[0] = 0x01;
ret = tm6000_snd_control_msg(tm6000_dev, 0x10, 0x701e, 0x00, data, 0x1);
msleep(15);
break;
}
kfree(data);
return 0;
};
int pseudo_zl10353_set_frontend(struct dvb_frontend *fe,
struct dvb_frontend_parameters *p)
{
struct tm6000_core *tm6000_dev = fe->dvb->priv;
u32 status;
if(p != NULL) {
// mutex_lock(&tm6000_dev->mutex);
pseudo_zl10353_pll(tm6000_dev, p);
// mutex_unlock(&tm6000_dev->mutex);
}
if(tm6000_dev->dvb->frontend->ops.read_status) {
tm6000_dev->dvb->frontend->ops.read_status(tm6000_dev->dvb->frontend, &status);
printk(KERN_ALERT "demodulator status: FE_HAS_CARRIER %i \n", (status & FE_HAS_CARRIER));
printk(KERN_ALERT "demodulator status: FE_HAS_VITERBI %i \n", (status & FE_HAS_VITERBI));
printk(KERN_ALERT "demodulator status: FE_HAS_LOCK %i \n", (status & FE_HAS_LOCK));
printk(KERN_ALERT "demodulator status: FE_HAS_SYNC %i \n", (status & FE_HAS_SYNC));
printk(KERN_ALERT "demodulator status: FE_HAS_SIGNAL %i \n", (status & FE_HAS_SIGNAL));
}
else {
printk(KERN_ALERT "pseudo zl10353: couldn't read demodulator status\n");
}
return 0;
}
int pseudo_zl10353_read_status(struct dvb_frontend *fe, fe_status_t *status)
{
*status = FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK | FE_HAS_SIGNAL;
return 0;
}
struct dvb_frontend* pseudo_zl10353_attach(struct tm6000_core *dev,
const struct zl10353_config *config,
struct i2c_adapter *i2c)
{
struct tm6000_dvb *dvb = dev->dvb;
dvb->frontend = zl10353_attach(config, i2c);
if(!dvb->frontend) {
return NULL;
}
/* override some functions with our implementations */
dvb->frontend->ops.set_frontend = pseudo_zl10353_set_frontend;
dvb->frontend->ops.read_status = pseudo_zl10353_read_status;
dvb->frontend->frontend_priv = dev;
return dvb->frontend;
}
/*
hack.h - hackish code that needs to be improved (or removed) at a
later point
Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.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 version 2
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.
*/
#ifndef HACK_H
#define HACK_H
#include <linux/i2c.h>
#include "zl10353.h"
#include "dvb_frontend.h"
struct tm6000_core;
int pseudo_zl103530_init(struct dvb_frontend *fe);
int pseudo_zl10353_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
int pseudo_zl10353_read_status(struct dvb_frontend *fe, fe_status_t *status);
int pseudo_zl10353_read_signal_strength(struct dvb_frontend* fe, u16* strength);
int pseudo_zl10353_read_snr(struct dvb_frontend *fe, u16 *snr);
struct dvb_frontend* pseudo_zl10353_attach(struct tm6000_core *dev,
const struct zl10353_config *config,
struct i2c_adapter *i2c);
#endif
...@@ -185,7 +185,19 @@ static int tm6000_init_dev(struct tm6000_core *dev) ...@@ -185,7 +185,19 @@ static int tm6000_init_dev(struct tm6000_core *dev)
dev->freq = f.frequency; dev->freq = f.frequency;
tm6000_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f); tm6000_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f);
if(dev->caps.has_dvb) {
dev->dvb = kzalloc(sizeof(*(dev->dvb)), GFP_KERNEL);
if(!dev->dvb) {
rc = -ENOMEM;
goto err;
}
rc = tm6000_dvb_register(dev);
if(rc < 0) {
kfree(dev->dvb);
dev->dvb = NULL;
goto err;
}
}
err: err:
mutex_unlock(&dev->lock); mutex_unlock(&dev->lock);
return rc; return rc;
...@@ -389,6 +401,11 @@ static void tm6000_usb_disconnect(struct usb_interface *interface) ...@@ -389,6 +401,11 @@ static void tm6000_usb_disconnect(struct usb_interface *interface)
mutex_lock(&dev->lock); mutex_lock(&dev->lock);
if(dev->dvb) {
tm6000_dvb_unregister(dev);
kfree(dev->dvb);
}
tm6000_v4l2_unregister(dev); tm6000_v4l2_unregister(dev);
tm6000_i2c_unregister(dev); tm6000_i2c_unregister(dev);
......
...@@ -3,6 +3,9 @@ ...@@ -3,6 +3,9 @@
Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org> Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
- DVB-T support
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation version 2 the Free Software Foundation version 2
...@@ -207,6 +210,32 @@ int tm6000_init_analog_mode (struct tm6000_core *dev) ...@@ -207,6 +210,32 @@ int tm6000_init_analog_mode (struct tm6000_core *dev)
return 0; return 0;
} }
int tm6000_init_digital_mode (struct tm6000_core *dev)
{
tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00ff, 0x08);
tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00ff, 0x00);
tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x003f, 0x01);
tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00df, 0x08);
tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e2, 0x0c);
tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00e8, 0xff);
tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00eb, 0xd8);
tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00c0, 0x40);
tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00c1, 0xd0);
tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00c3, 0x09);
tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00da, 0x37);
tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00d1, 0xd8);
tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00d2, 0xc0);
tm6000_set_reg (dev, REQ_07_SET_GET_AVREG, 0x00d6, 0x60);
msleep(50);
tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x01);
tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
msleep(100);
return 0;
}
/* The meaning of those initializations are unknown */ /* The meaning of those initializations are unknown */
u8 init_tab[][2] = { u8 init_tab[][2] = {
......
/*
tm6000-dvb.c - dvb-t support for TM5600/TM6000 USB video capture devices
Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.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 version 2
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/usb.h>
#include "tm6000.h"
#include "tm6000-regs.h"
#include "hack.h"
#include "zl10353.h"
#include <media/tuner.h>
static void tm6000_urb_received(struct urb *urb)
{
int ret;
struct tm6000_core* dev = urb->context;
if(urb->status != 0){
printk(KERN_ERR "tm6000: status != 0\n");
}
else if(urb->actual_length>0){
dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer,
urb->actual_length);
}
if(dev->dvb->streams > 0) {
ret = usb_submit_urb(urb, GFP_ATOMIC);
if(ret < 0) {
printk(KERN_ERR "tm6000: error %s\n", __FUNCTION__);
kfree(urb->transfer_buffer);
usb_free_urb(urb);
}
}
}
int tm6000_start_stream(struct tm6000_core *dev)
{
int ret;
unsigned int pipe, maxPaketSize;
struct tm6000_dvb *dvb = dev->dvb;
printk(KERN_INFO "tm6000: got start stream request %s\n",__FUNCTION__);
tm6000_init_digital_mode(dev);
// ret = usb_set_interface(dev->udev, 0, 1);
// if (ret<0)
// return ret;
/*
ret = tm6000_set_led_status(tm6000_dev, 0x1);
if(ret < 0) {
return -1;
}
*/
dvb->bulk_urb = usb_alloc_urb(0, GFP_KERNEL);
if(dvb->bulk_urb == NULL) {
printk(KERN_ERR "tm6000: couldn't allocate urb\n");
return -ENOMEM;
}
maxPaketSize = dev->bulk_in->desc.wMaxPacketSize;
dvb->bulk_urb->transfer_buffer = kzalloc(maxPaketSize, GFP_KERNEL);
if(dvb->bulk_urb->transfer_buffer == NULL) {
usb_free_urb(dvb->bulk_urb);
printk(KERN_ERR "tm6000: couldn't allocate transfer buffer!\n");
return -ENOMEM;
}
pipe = usb_rcvbulkpipe(dev->udev, dev->bulk_in->desc.bEndpointAddress
& USB_ENDPOINT_NUMBER_MASK);
usb_fill_bulk_urb(dvb->bulk_urb, dev->udev, pipe,
dvb->bulk_urb->transfer_buffer,
maxPaketSize,
tm6000_urb_received, dev);
ret = usb_clear_halt(dev->udev, pipe);
if(ret < 0) {
printk(KERN_ERR "tm6000: error %i in %s during pipe reset\n",ret,__FUNCTION__);
// return ret;
}
else {
printk(KERN_ERR "tm6000: pipe resetted\n");
}
// mutex_lock(&tm6000_driver.open_close_mutex);
ret = usb_submit_urb(dvb->bulk_urb, GFP_KERNEL);
// mutex_unlock(&tm6000_driver.open_close_mutex);
if (ret) {
printk(KERN_ERR "tm6000: submit of urb failed (error=%i)\n",ret);
kfree(dvb->bulk_urb->transfer_buffer);
usb_free_urb(dvb->bulk_urb);
return ret;
}
return 0;
}
void tm6000_stop_stream(struct tm6000_core *dev)
{
struct tm6000_dvb *dvb = dev->dvb;
// tm6000_set_led_status(tm6000_dev, 0x0);
if(dvb->bulk_urb) {
usb_kill_urb(dvb->bulk_urb);
kfree(dvb->bulk_urb->transfer_buffer);
usb_free_urb(dvb->bulk_urb);
dvb->bulk_urb = NULL;
}
}
int tm6000_start_feed(struct dvb_demux_feed *feed)
{
struct dvb_demux *demux = feed->demux;
struct tm6000_core *dev = demux->priv;
struct tm6000_dvb *dvb = dev->dvb;
printk(KERN_INFO "tm6000: got start feed request %s\n",__FUNCTION__);
mutex_lock(&dvb->mutex);
if(dvb->streams == 0) {
dvb->streams = 1;
// mutex_init(&tm6000_dev->streaming_mutex);
tm6000_start_stream(dev);
}
else {
++(dvb->streams);
}
mutex_unlock(&dvb->mutex);
return 0;
}
int tm6000_stop_feed(struct dvb_demux_feed *feed) {
struct dvb_demux *demux = feed->demux;
struct tm6000_core *dev = demux->priv;
struct tm6000_dvb *dvb = dev->dvb;
printk(KERN_INFO "tm6000: got stop feed request %s\n",__FUNCTION__);
mutex_lock(&dvb->mutex);
--dvb->streams;
if(0 == dvb->streams) {
tm6000_stop_stream(dev);
// mutex_destroy(&tm6000_dev->streaming_mutex);
}
mutex_unlock(&dvb->mutex);
// mutex_destroy(&tm6000_dev->streaming_mutex);
return 0;
}
int tm6000_dvb_attach_frontend(struct tm6000_core *dev)
{
struct tm6000_dvb *dvb = dev->dvb;
if(dev->caps.has_zl10353) {
struct zl10353_config config =
{.demod_address = dev->demod_addr >> 1,
.no_tuner = 1,
// .input_frequency = 0x19e9,
// .r56_agc_targets = 0x1c,
};
dvb->frontend = pseudo_zl10353_attach(dev, &config,
&dev->i2c_adap);
}
else {
printk(KERN_ERR "tm6000: no frontend defined for the device!\n");
return -1;
}
if(dvb->frontend) {
return 0;
}
else {
return -1;
}
}
int tm6000_dvb_register(struct tm6000_core *dev)
{
int ret = -1;
struct tm6000_dvb *dvb = dev->dvb;
mutex_init(&dvb->mutex);
dvb->streams = 0;
/* attach the frontend */
ret = tm6000_dvb_attach_frontend(dev);
if(ret < 0) {
printk(KERN_ERR "tm6000: couldn't attach the frontend!\n");
// goto err;
}
ret = dvb_register_adapter(&dvb->adapter, "Trident TVMaster 6000 DVB-T",
THIS_MODULE, &dev->udev->dev);
dvb->adapter.priv = dev;
if(dvb->frontend) {
ret = dvb_register_frontend(&dvb->adapter, dvb->frontend);
if(ret < 0) {
printk("tm6000: couldn't register frontend\n");
goto adapter_err;
}
// attach the tuner like this for now
tm6000_i2c_call_clients(dev, VIDIOC_INT_DVB_TUNER_ATTACH, dvb->frontend);
printk("tm6000: XC2028/3028 asked to be attached to frontend!\n");
}
else {
printk("tm6000: no frontend found\n");
}
dvb->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING
| DMX_MEMORY_BASED_FILTERING;
dvb->demux.priv = dev;
dvb->demux.filternum = 256;
dvb->demux.feednum = 256;
dvb->demux.start_feed = tm6000_start_feed;
dvb->demux.stop_feed = tm6000_stop_feed;
dvb->demux.write_to_decoder = NULL;
ret = dvb_dmx_init(&dvb->demux);
if(ret < 0) {
printk("tm6000: dvb_dmx_init failed (errno = %d)\n", ret);
goto frontend_err;
}
dvb->dmxdev.filternum = dev->dvb->demux.filternum;
dvb->dmxdev.demux = &dev->dvb->demux.dmx;
dvb->dmxdev.capabilities = 0;
ret = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
if(ret < 0) {
printk("tm6000: dvb_dmxdev_init failed (errno = %d)\n", ret);
goto dvb_dmx_err;
}
return 0;
dvb_dmx_err:
dvb_dmx_release(&dvb->demux);
frontend_err:
if(dvb->frontend) {
dvb_unregister_frontend(dvb->frontend);
}
adapter_err:
dvb_unregister_adapter(&dvb->adapter);
err:
return ret;
}
void tm6000_dvb_unregister(struct tm6000_core *dev)
{
struct tm6000_dvb *dvb = dev->dvb;
if(dvb->bulk_urb != NULL) {
struct urb *bulk_urb = dvb->bulk_urb;
kfree(bulk_urb->transfer_buffer);
bulk_urb->transfer_buffer = NULL;
usb_unlink_urb(bulk_urb);
usb_free_urb(bulk_urb);
}
// mutex_lock(&tm6000_driver.open_close_mutex);
if(dvb->frontend) {
dvb_unregister_frontend(dvb->frontend);
}
dvb_dmxdev_release(&dvb->dmxdev);
dvb_dmx_release(&dvb->demux);
dvb_unregister_adapter(&dvb->adapter);
mutex_destroy(&dvb->mutex);
// mutex_unlock(&tm6000_driver.open_close_mutex);
}
...@@ -3,6 +3,9 @@ ...@@ -3,6 +3,9 @@
Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org> Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com>
- DVB-T support
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation version 2 the Free Software Foundation version 2
...@@ -27,6 +30,11 @@ ...@@ -27,6 +30,11 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/dvb/frontend.h>
#include "dvb_demux.h"
#include "dvb_frontend.h"
#include "dmxdev.h"
#define TM6000_VERSION KERNEL_VERSION(0, 0, 1) #define TM6000_VERSION KERNEL_VERSION(0, 0, 1)
/* Inputs */ /* Inputs */
...@@ -97,12 +105,23 @@ struct tm6000_capabilities { ...@@ -97,12 +105,23 @@ struct tm6000_capabilities {
unsigned int has_eeprom:1; unsigned int has_eeprom:1;
}; };
struct tm6000_dvb {
struct dvb_adapter adapter;
struct dvb_demux demux;
struct dvb_frontend *frontend;
struct dmxdev dmxdev;
unsigned int streams;
struct urb *bulk_urb;
struct mutex mutex;
};
struct tm6000_core { struct tm6000_core {
/* generic device properties */ /* generic device properties */
char name[30]; /* name (including minor) of the device */ char name[30]; /* name (including minor) of the device */
int model; /* index in the device_data struct */ int model; /* index in the device_data struct */
int devno; /* marks the number of this device */ int devno; /* marks the number of this device */
v4l2_std_id norm; /* Current norm */
v4l2_std_id norm; /* Current norm */
enum tm6000_core_state state; enum tm6000_core_state state;
...@@ -136,6 +155,9 @@ struct tm6000_core { ...@@ -136,6 +155,9 @@ struct tm6000_core {
enum tm6000_mode mode; enum tm6000_mode mode;
/* DVB-T support */
struct tm6000_dvb *dvb;
/* locks */ /* locks */
struct mutex lock; struct mutex lock;
...@@ -181,9 +203,13 @@ int tm6000_init (struct tm6000_core *dev); ...@@ -181,9 +203,13 @@ int tm6000_init (struct tm6000_core *dev);
int tm6000_init_after_firmware (struct tm6000_core *dev); int tm6000_init_after_firmware (struct tm6000_core *dev);
int tm6000_init_analog_mode (struct tm6000_core *dev); int tm6000_init_analog_mode (struct tm6000_core *dev);
int tm6000_init_digital_mode (struct tm6000_core *dev);
int tm6000_set_standard (struct tm6000_core *dev, v4l2_std_id *norm); int tm6000_set_standard (struct tm6000_core *dev, v4l2_std_id *norm);
int tm6000_set_audio_bitrate (struct tm6000_core *dev, int bitrate); int tm6000_set_audio_bitrate (struct tm6000_core *dev, int bitrate);
int tm6000_dvb_register(struct tm6000_core *dev);
void tm6000_dvb_unregister(struct tm6000_core *dev);
int tm6000_v4l2_register(struct tm6000_core *dev); int tm6000_v4l2_register(struct tm6000_core *dev);
int tm6000_v4l2_unregister(struct tm6000_core *dev); int tm6000_v4l2_unregister(struct tm6000_core *dev);
int tm6000_v4l2_exit(void); int tm6000_v4l2_exit(void);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment