Commit b6a235b1 authored by Johannes Stezenbach's avatar Johannes Stezenbach Committed by Linus Torvalds

[PATCH] dvb: drop obsolete dibusb driver

Remove the dibusb driver which has been obsoleted by the generalized dvb-usb
driver.
Signed-off-by: default avatarPatrick Boettcher <pb@linuxtv.org>
Signed-off-by: default avatarJohannes Stezenbach <js@linuxtv.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 3e05d2b8
This diff is collapsed.
......@@ -29,7 +29,6 @@ comment "Supported USB Adapters"
depends on DVB_CORE && USB
source "drivers/media/dvb/ttusb-budget/Kconfig"
source "drivers/media/dvb/ttusb-dec/Kconfig"
source "drivers/media/dvb/dibusb/Kconfig"
source "drivers/media/dvb/cinergyT2/Kconfig"
comment "Supported FlexCopII (B2C2) Adapters"
......
......@@ -2,4 +2,4 @@
# Makefile for the kernel multimedia device drivers.
#
obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ dibusb/ cinergyT2/
obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/
config DVB_DIBUSB
tristate "DiBcom USB DVB-T devices (see help for a complete device list)"
depends on DVB_CORE && USB
select FW_LOADER
select DVB_DIB3000MB
select DVB_DIB3000MC
select DVB_MT352
help
Support for USB 1.1 and 2.0 DVB-T devices based on reference designs made by
DiBcom (http://www.dibcom.fr) and C&E.
Devices supported by this driver:
TwinhanDTV USB-Ter (VP7041)
TwinhanDTV Magic Box (VP7041e)
KWorld/JetWay/ADSTech V-Stream XPERT DTV - DVB-T USB1.1 and USB2.0
Hama DVB-T USB-Box
DiBcom reference devices (non-public)
Ultima Electronic/Artec T1 USB TVBOX
Compro Videomate DVB-U2000 - DVB-T USB
Grandtec DVB-T USB
Avermedia AverTV DVBT USB
Artec T1 USB1.1 and USB2.0 boxes
Yakumo/Typhoon DVB-T USB2.0
Hanftek UMT-010 USB2.0
Hauppauge WinTV NOVA-T USB2
The VP7041 seems to be identical to "CTS Portable" (Chinese
Television System).
These devices can be understood as budget ones, they "only" deliver
(a part of) the MPEG2 transport stream.
A firmware is needed to get the device working. See Documentation/dvb/README.dibusb
details.
Say Y if you own such a device and want to use it. You should build it as
a module.
config DVB_DIBUSB_MISDESIGNED_DEVICES
bool "Enable support for some misdesigned (see help) devices, which identify with wrong IDs"
depends on DVB_DIBUSB
help
Somehow Artec/Ultima Electronic forgot to program the eeprom of some of their
USB1.1/USB2.0 devices.
So comes that they identify with the default Vendor and Product ID of the Cypress
CY7C64613 (AN2235) or Cypress FX2.
Affected device IDs:
0x0574:0x2235 (Artec T1 USB1.1, cold)
0x04b4:0x8613 (Artec T1 USB2.0, cold)
0x0574:0x1002 (Artec T1 USB2.0, warm)
0x0574:0x2131 (aged DiBcom USB1.1 test device)
Say Y if your device has one of the mentioned IDs.
config DVB_DIBCOM_DEBUG
bool "Enable extended debug support for DiBcom USB device"
depends on DVB_DIBUSB
help
Say Y if you want to enable debuging. See modinfo dvb-dibusb for
debug levels.
dvb-dibusb-objs = dvb-dibusb-core.o \
dvb-dibusb-dvb.o \
dvb-dibusb-fe-i2c.o \
dvb-dibusb-firmware.o \
dvb-dibusb-remote.o \
dvb-dibusb-usb.o \
dvb-fe-dtt200u.o
obj-$(CONFIG_DVB_DIBUSB) += dvb-dibusb.o
EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
This diff is collapsed.
/*
* dvb-dibusb-dvb.c is part of the driver for mobile USB Budget DVB-T devices
* based on reference design made by DiBcom (http://www.dibcom.fr/)
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
* see dvb-dibusb-core.c for more copyright details.
*
* This file contains functions for initializing and handling the
* linux-dvb API.
*/
#include "dvb-dibusb.h"
#include <linux/usb.h>
#include <linux/version.h>
static u32 urb_compl_count;
/*
* MPEG2 TS DVB stuff
*/
void dibusb_urb_complete(struct urb *urb, struct pt_regs *ptregs)
{
struct usb_dibusb *dib = urb->context;
deb_ts("urb complete feedcount: %d, status: %d, length: %d\n",dib->feedcount,urb->status,
urb->actual_length);
urb_compl_count++;
if (urb_compl_count % 1000 == 0)
deb_info("%d urbs completed so far.\n",urb_compl_count);
switch (urb->status) {
case 0: /* success */
case -ETIMEDOUT: /* NAK */
break;
case -ECONNRESET: /* kill */
case -ENOENT:
case -ESHUTDOWN:
return;
default: /* error */
deb_ts("urb completition error %d.", urb->status);
break;
}
if (dib->feedcount > 0 && urb->actual_length > 0) {
if (dib->init_state & DIBUSB_STATE_DVB)
dvb_dmx_swfilter(&dib->demux, (u8*) urb->transfer_buffer,urb->actual_length);
} else
deb_ts("URB dropped because of feedcount.\n");
usb_submit_urb(urb,GFP_ATOMIC);
}
static int dibusb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
{
struct usb_dibusb *dib = dvbdmxfeed->demux->priv;
int newfeedcount;
if (dib == NULL)
return -ENODEV;
newfeedcount = dib->feedcount + (onoff ? 1 : -1);
/*
* stop feed before setting a new pid if there will be no pid anymore
*/
if (newfeedcount == 0) {
deb_ts("stop feeding\n");
if (dib->xfer_ops.fifo_ctrl != NULL) {
if (dib->xfer_ops.fifo_ctrl(dib->fe,0)) {
err("error while inhibiting fifo.");
return -ENODEV;
}
}
dibusb_streaming(dib,0);
}
dib->feedcount = newfeedcount;
/* activate the pid on the device specific pid_filter */
deb_ts("setting pid: %5d %04x at index %d '%s'\n",dvbdmxfeed->pid,dvbdmxfeed->pid,dvbdmxfeed->index,onoff ? "on" : "off");
if (dib->pid_parse && dib->xfer_ops.pid_ctrl != NULL)
dib->xfer_ops.pid_ctrl(dib->fe,dvbdmxfeed->index,dvbdmxfeed->pid,onoff);
/*
* start the feed if this was the first pid to set and there is still a pid
* for reception.
*/
if (dib->feedcount == onoff && dib->feedcount > 0) {
deb_ts("controlling pid parser\n");
if (dib->xfer_ops.pid_parse != NULL) {
if (dib->xfer_ops.pid_parse(dib->fe,dib->pid_parse) < 0) {
err("could not handle pid_parser");
}
}
deb_ts("start feeding\n");
if (dib->xfer_ops.fifo_ctrl != NULL) {
if (dib->xfer_ops.fifo_ctrl(dib->fe,1)) {
err("error while enabling fifo.");
return -ENODEV;
}
}
dibusb_streaming(dib,1);
}
return 0;
}
static int dibusb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
{
deb_ts("start pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid,dvbdmxfeed->type);
return dibusb_ctrl_feed(dvbdmxfeed,1);
}
static int dibusb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
{
deb_ts("stop pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid, dvbdmxfeed->type);
return dibusb_ctrl_feed(dvbdmxfeed,0);
}
int dibusb_dvb_init(struct usb_dibusb *dib)
{
int ret;
urb_compl_count = 0;
if ((ret = dvb_register_adapter(&dib->adapter, DRIVER_DESC,
THIS_MODULE)) < 0) {
deb_info("dvb_register_adapter failed: error %d", ret);
goto err;
}
dib->adapter.priv = dib;
/* i2c is done in dibusb_i2c_init */
dib->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
dib->demux.priv = (void *)dib;
/* get pidcount from demod */
dib->demux.feednum = dib->demux.filternum = 255;
dib->demux.start_feed = dibusb_start_feed;
dib->demux.stop_feed = dibusb_stop_feed;
dib->demux.write_to_decoder = NULL;
if ((ret = dvb_dmx_init(&dib->demux)) < 0) {
err("dvb_dmx_init failed: error %d",ret);
goto err_dmx;
}
dib->dmxdev.filternum = dib->demux.filternum;
dib->dmxdev.demux = &dib->demux.dmx;
dib->dmxdev.capabilities = 0;
if ((ret = dvb_dmxdev_init(&dib->dmxdev, &dib->adapter)) < 0) {
err("dvb_dmxdev_init failed: error %d",ret);
goto err_dmx_dev;
}
dvb_net_init(&dib->adapter, &dib->dvb_net, &dib->demux.dmx);
goto success;
err_dmx_dev:
dvb_dmx_release(&dib->demux);
err_dmx:
dvb_unregister_adapter(&dib->adapter);
err:
return ret;
success:
dib->init_state |= DIBUSB_STATE_DVB;
return 0;
}
int dibusb_dvb_exit(struct usb_dibusb *dib)
{
if (dib->init_state & DIBUSB_STATE_DVB) {
dib->init_state &= ~DIBUSB_STATE_DVB;
deb_info("unregistering DVB part\n");
dvb_net_release(&dib->dvb_net);
dib->demux.dmx.close(&dib->demux.dmx);
dvb_dmxdev_release(&dib->dmxdev);
dvb_dmx_release(&dib->demux);
dvb_unregister_adapter(&dib->adapter);
}
return 0;
}
This diff is collapsed.
/*
* dvb-dibusb-firmware.c is part of the driver for mobile USB Budget DVB-T devices
* based on reference design made by DiBcom (http://www.dibcom.fr/)
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
* see dvb-dibusb-core.c for more copyright details.
*
* This file contains functions for downloading the firmware to the device.
*/
#include "dvb-dibusb.h"
#include <linux/firmware.h>
#include <linux/usb.h>
/*
* load a firmware packet to the device
*/
static int dibusb_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 len)
{
return usb_control_msg(udev, usb_sndctrlpipe(udev,0),
0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000);
}
int dibusb_loadfirmware(struct usb_device *udev, struct dibusb_usb_device *dibdev)
{
const struct firmware *fw = NULL;
u16 addr;
u8 *b,*p;
int ret = 0,i;
if ((ret = request_firmware(&fw, dibdev->dev_cl->firmware, &udev->dev)) != 0) {
err("did not find the firmware file. (%s) "
"Please see linux/Documentation/dvb/ for more details on firmware-problems.",
dibdev->dev_cl->firmware);
return ret;
}
info("downloading firmware from file '%s'.",dibdev->dev_cl->firmware);
p = kmalloc(fw->size,GFP_KERNEL);
if (p != NULL) {
u8 reset;
/*
* you cannot use the fw->data as buffer for
* usb_control_msg, a new buffer has to be
* created
*/
memcpy(p,fw->data,fw->size);
/* stop the CPU */
reset = 1;
if ((ret = dibusb_writemem(udev,dibdev->dev_cl->usb_ctrl->cpu_cs_register,&reset,1)) != 1)
err("could not stop the USB controller CPU.");
for(i = 0; p[i+3] == 0 && i < fw->size; ) {
b = (u8 *) &p[i];
addr = *((u16 *) &b[1]);
ret = dibusb_writemem(udev,addr,&b[4],b[0]);
if (ret != b[0]) {
err("error while transferring firmware "
"(transferred size: %d, block size: %d)",
ret,b[0]);
ret = -EINVAL;
break;
}
i += 5 + b[0];
}
/* length in ret */
if (ret > 0)
ret = 0;
/* restart the CPU */
reset = 0;
if (ret || dibusb_writemem(udev,dibdev->dev_cl->usb_ctrl->cpu_cs_register,&reset,1) != 1) {
err("could not restart the USB controller CPU.");
ret = -EINVAL;
}
kfree(p);
} else {
ret = -ENOMEM;
}
release_firmware(fw);
return ret;
}
/*
* dvb-dibusb-remote.c is part of the driver for mobile USB Budget DVB-T devices
* based on reference design made by DiBcom (http://www.dibcom.fr/)
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
* see dvb-dibusb-core.c for more copyright details.
*
* This file contains functions for handling the event device on the software
* side and the remote control on the hardware side.
*/
#include "dvb-dibusb.h"
/* Table to map raw key codes to key events. This should not be hard-wired
into the kernel. */
static const struct { u8 c0, c1, c2; uint32_t key; } nec_rc_keys [] =
{
/* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */
{ 0x00, 0xff, 0x16, KEY_POWER },
{ 0x00, 0xff, 0x10, KEY_MUTE },
{ 0x00, 0xff, 0x03, KEY_1 },
{ 0x00, 0xff, 0x01, KEY_2 },
{ 0x00, 0xff, 0x06, KEY_3 },
{ 0x00, 0xff, 0x09, KEY_4 },
{ 0x00, 0xff, 0x1d, KEY_5 },
{ 0x00, 0xff, 0x1f, KEY_6 },
{ 0x00, 0xff, 0x0d, KEY_7 },
{ 0x00, 0xff, 0x19, KEY_8 },
{ 0x00, 0xff, 0x1b, KEY_9 },
{ 0x00, 0xff, 0x15, KEY_0 },
{ 0x00, 0xff, 0x05, KEY_CHANNELUP },
{ 0x00, 0xff, 0x02, KEY_CHANNELDOWN },
{ 0x00, 0xff, 0x1e, KEY_VOLUMEUP },
{ 0x00, 0xff, 0x0a, KEY_VOLUMEDOWN },
{ 0x00, 0xff, 0x11, KEY_RECORD },
{ 0x00, 0xff, 0x17, KEY_FAVORITES }, /* Heart symbol - Channel list. */
{ 0x00, 0xff, 0x14, KEY_PLAY },
{ 0x00, 0xff, 0x1a, KEY_STOP },
{ 0x00, 0xff, 0x40, KEY_REWIND },
{ 0x00, 0xff, 0x12, KEY_FASTFORWARD },
{ 0x00, 0xff, 0x0e, KEY_PREVIOUS }, /* Recall - Previous channel. */
{ 0x00, 0xff, 0x4c, KEY_PAUSE },
{ 0x00, 0xff, 0x4d, KEY_SCREEN }, /* Full screen mode. */
{ 0x00, 0xff, 0x54, KEY_AUDIO }, /* MTS - Switch to secondary audio. */
/* additional keys TwinHan VisionPlus, the Artec seemingly not have */
{ 0x00, 0xff, 0x0c, KEY_CANCEL }, /* Cancel */
{ 0x00, 0xff, 0x1c, KEY_EPG }, /* EPG */
{ 0x00, 0xff, 0x00, KEY_TAB }, /* Tab */
{ 0x00, 0xff, 0x48, KEY_INFO }, /* Preview */
{ 0x00, 0xff, 0x04, KEY_LIST }, /* RecordList */
{ 0x00, 0xff, 0x0f, KEY_TEXT }, /* Teletext */
/* Key codes for the KWorld/ADSTech/JetWay remote. */
{ 0x86, 0x6b, 0x12, KEY_POWER },
{ 0x86, 0x6b, 0x0f, KEY_SELECT }, /* source */
{ 0x86, 0x6b, 0x0c, KEY_UNKNOWN }, /* scan */
{ 0x86, 0x6b, 0x0b, KEY_EPG },
{ 0x86, 0x6b, 0x10, KEY_MUTE },
{ 0x86, 0x6b, 0x01, KEY_1 },
{ 0x86, 0x6b, 0x02, KEY_2 },
{ 0x86, 0x6b, 0x03, KEY_3 },
{ 0x86, 0x6b, 0x04, KEY_4 },
{ 0x86, 0x6b, 0x05, KEY_5 },
{ 0x86, 0x6b, 0x06, KEY_6 },
{ 0x86, 0x6b, 0x07, KEY_7 },
{ 0x86, 0x6b, 0x08, KEY_8 },
{ 0x86, 0x6b, 0x09, KEY_9 },
{ 0x86, 0x6b, 0x0a, KEY_0 },
{ 0x86, 0x6b, 0x18, KEY_ZOOM },
{ 0x86, 0x6b, 0x1c, KEY_UNKNOWN }, /* preview */
{ 0x86, 0x6b, 0x13, KEY_UNKNOWN }, /* snap */
{ 0x86, 0x6b, 0x00, KEY_UNDO },
{ 0x86, 0x6b, 0x1d, KEY_RECORD },
{ 0x86, 0x6b, 0x0d, KEY_STOP },
{ 0x86, 0x6b, 0x0e, KEY_PAUSE },
{ 0x86, 0x6b, 0x16, KEY_PLAY },
{ 0x86, 0x6b, 0x11, KEY_BACK },
{ 0x86, 0x6b, 0x19, KEY_FORWARD },
{ 0x86, 0x6b, 0x14, KEY_UNKNOWN }, /* pip */
{ 0x86, 0x6b, 0x15, KEY_ESC },
{ 0x86, 0x6b, 0x1a, KEY_UP },
{ 0x86, 0x6b, 0x1e, KEY_DOWN },
{ 0x86, 0x6b, 0x1f, KEY_LEFT },
{ 0x86, 0x6b, 0x1b, KEY_RIGHT },
};
/* Hauppauge NOVA-T USB2 keys */
static const struct { u16 raw; uint32_t key; } haupp_rc_keys [] = {
{ 0xddf, KEY_GOTO },
{ 0xdef, KEY_POWER },
{ 0xce7, KEY_TV },
{ 0xcc7, KEY_VIDEO },
{ 0xccf, KEY_AUDIO },
{ 0xcd7, KEY_MEDIA },
{ 0xcdf, KEY_EPG },
{ 0xca7, KEY_UP },
{ 0xc67, KEY_RADIO },
{ 0xcb7, KEY_LEFT },
{ 0xd2f, KEY_OK },
{ 0xcbf, KEY_RIGHT },
{ 0xcff, KEY_BACK },
{ 0xcaf, KEY_DOWN },
{ 0xc6f, KEY_MENU },
{ 0xc87, KEY_VOLUMEUP },
{ 0xc8f, KEY_VOLUMEDOWN },
{ 0xc97, KEY_CHANNEL },
{ 0xc7f, KEY_MUTE },
{ 0xd07, KEY_CHANNELUP },
{ 0xd0f, KEY_CHANNELDOWN },
{ 0xdbf, KEY_RECORD },
{ 0xdb7, KEY_STOP },
{ 0xd97, KEY_REWIND },
{ 0xdaf, KEY_PLAY },
{ 0xda7, KEY_FASTFORWARD },
{ 0xd27, KEY_LAST }, /* Skip backwards */
{ 0xd87, KEY_PAUSE },
{ 0xcf7, KEY_NEXT },
{ 0xc07, KEY_0 },
{ 0xc0f, KEY_1 },
{ 0xc17, KEY_2 },
{ 0xc1f, KEY_3 },
{ 0xc27, KEY_4 },
{ 0xc2f, KEY_5 },
{ 0xc37, KEY_6 },
{ 0xc3f, KEY_7 },
{ 0xc47, KEY_8 },
{ 0xc4f, KEY_9 },
{ 0xc57, KEY_KPASTERISK },
{ 0xc77, KEY_GRAVE }, /* # */
{ 0xc5f, KEY_RED },
{ 0xd77, KEY_GREEN },
{ 0xdc7, KEY_YELLOW },
{ 0xd4f, KEY_BLUE},
};
static int dibusb_key2event_nec(struct usb_dibusb *dib,u8 rb[5])
{
int i;
switch (rb[0]) {
case DIBUSB_RC_NEC_KEY_PRESSED:
/* rb[1-3] is the actual key, rb[4] is a checksum */
deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
rb[1], rb[2], rb[3], rb[4]);
if ((0xff - rb[3]) != rb[4]) {
deb_rc("remote control checksum failed.\n");
break;
}
/* See if we can match the raw key code. */
for (i = 0; i < sizeof(nec_rc_keys)/sizeof(nec_rc_keys[0]); i++) {
if (nec_rc_keys[i].c0 == rb[1] &&
nec_rc_keys[i].c1 == rb[2] &&
nec_rc_keys[i].c2 == rb[3]) {
dib->last_event = nec_rc_keys[i].key;
return 1;
}
}
break;
case DIBUSB_RC_NEC_KEY_REPEATED:
/* rb[1]..rb[4] are always zero.*/
/* Repeats often seem to occur so for the moment just ignore this. */
return 0;
case DIBUSB_RC_NEC_EMPTY: /* No (more) remote control keys. */
default:
break;
}
return -1;
}
static int dibusb_key2event_hauppauge(struct usb_dibusb *dib,u8 rb[4])
{
u16 raw;
int i,state;
switch (rb[0]) {
case DIBUSB_RC_HAUPPAUGE_KEY_PRESSED:
raw = ((rb[1] & 0x0f) << 8) | rb[2];
state = !!(rb[1] & 0x40);
deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x to %04x state: %d\n",rb[1],rb[2],rb[3],raw,state);
for (i = 0; i < sizeof(haupp_rc_keys)/sizeof(haupp_rc_keys[0]); i++) {
if (haupp_rc_keys[i].raw == raw) {
if (dib->last_event == haupp_rc_keys[i].key &&
dib->last_state == state) {
deb_rc("key repeat\n");
return 0;
} else {
dib->last_event = haupp_rc_keys[i].key;
dib->last_state = state;
return 1;
}
}
}
break;
case DIBUSB_RC_HAUPPAUGE_KEY_EMPTY:
default:
break;
}
return -1;
}
/*
* Read the remote control and feed the appropriate event.
* NEC protocol is used for remote controls
*/
static int dibusb_read_remote_control(struct usb_dibusb *dib)
{
u8 b[1] = { DIBUSB_REQ_POLL_REMOTE }, rb[5];
int ret,event = 0;
if ((ret = dibusb_readwrite_usb(dib,b,1,rb,5)))
return ret;
switch (dib->dibdev->dev_cl->remote_type) {
case DIBUSB_RC_NEC_PROTOCOL:
event = dibusb_key2event_nec(dib,rb);
break;
case DIBUSB_RC_HAUPPAUGE_PROTO:
event = dibusb_key2event_hauppauge(dib,rb);
default:
break;
}
/* key repeat */
if (event == 0)
if (++dib->repeat_key_count < dib->rc_key_repeat_count) {
deb_rc("key repeat dropped. (%d)\n",dib->repeat_key_count);
event = -1; /* skip this key repeat */
}
if (event == 1 || event == 0) {
deb_rc("Translated key 0x%04x\n",event);
/* Signal down and up events for this key. */
input_report_key(&dib->rc_input_dev, dib->last_event, 1);
input_report_key(&dib->rc_input_dev, dib->last_event, 0);
input_sync(&dib->rc_input_dev);
if (event == 1)
dib->repeat_key_count = 0;
}
return 0;
}
/* Remote-control poll function - called every dib->rc_query_interval ms to see
whether the remote control has received anything. */
static void dibusb_remote_query(void *data)
{
struct usb_dibusb *dib = (struct usb_dibusb *) data;
/* TODO: need a lock here. We can simply skip checking for the remote control
if we're busy. */
dibusb_read_remote_control(dib);
schedule_delayed_work(&dib->rc_query_work,
msecs_to_jiffies(dib->rc_query_interval));
}
int dibusb_remote_init(struct usb_dibusb *dib)
{
int i;
if (dib->dibdev->dev_cl->remote_type == DIBUSB_RC_NO)
return 0;
/* Initialise the remote-control structures.*/
init_input_dev(&dib->rc_input_dev);
dib->rc_input_dev.evbit[0] = BIT(EV_KEY);
dib->rc_input_dev.keycodesize = sizeof(unsigned char);
dib->rc_input_dev.keycodemax = KEY_MAX;
dib->rc_input_dev.name = DRIVER_DESC " remote control";
switch (dib->dibdev->dev_cl->remote_type) {
case DIBUSB_RC_NEC_PROTOCOL:
for (i=0; i<sizeof(nec_rc_keys)/sizeof(nec_rc_keys[0]); i++)
set_bit(nec_rc_keys[i].key, dib->rc_input_dev.keybit);
break;
case DIBUSB_RC_HAUPPAUGE_PROTO:
for (i=0; i<sizeof(haupp_rc_keys)/sizeof(haupp_rc_keys[0]); i++)
set_bit(haupp_rc_keys[i].key, dib->rc_input_dev.keybit);
break;
default:
break;
}
input_register_device(&dib->rc_input_dev);
INIT_WORK(&dib->rc_query_work, dibusb_remote_query, dib);
/* Start the remote-control polling. */
if (dib->rc_query_interval < 40)
dib->rc_query_interval = 100; /* default */
info("schedule remote query interval to %d msecs.",dib->rc_query_interval);
schedule_delayed_work(&dib->rc_query_work,msecs_to_jiffies(dib->rc_query_interval));
dib->init_state |= DIBUSB_STATE_REMOTE;
return 0;
}
int dibusb_remote_exit(struct usb_dibusb *dib)
{
if (dib->dibdev->dev_cl->remote_type == DIBUSB_RC_NO)
return 0;
if (dib->init_state & DIBUSB_STATE_REMOTE) {
cancel_delayed_work(&dib->rc_query_work);
flush_scheduled_work();
input_unregister_device(&dib->rc_input_dev);
}
dib->init_state &= ~DIBUSB_STATE_REMOTE;
return 0;
}
/*
* dvb-dibusb-usb.c is part of the driver for mobile USB Budget DVB-T devices
* based on reference design made by DiBcom (http://www.dibcom.fr/)
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
* see dvb-dibusb-core.c for more copyright details.
*
* This file contains functions for initializing and handling the
* usb specific stuff.
*/
#include "dvb-dibusb.h"
#include <linux/version.h>
#include <linux/pci.h>
int dibusb_readwrite_usb(struct usb_dibusb *dib, u8 *wbuf, u16 wlen, u8 *rbuf,
u16 rlen)
{
int actlen,ret = -ENOMEM;
if (wbuf == NULL || wlen == 0)
return -EINVAL;
if ((ret = down_interruptible(&dib->usb_sem)))
return ret;
debug_dump(wbuf,wlen);
ret = usb_bulk_msg(dib->udev,usb_sndbulkpipe(dib->udev,
dib->dibdev->dev_cl->pipe_cmd), wbuf,wlen,&actlen,
DIBUSB_I2C_TIMEOUT);
if (ret)
err("bulk message failed: %d (%d/%d)",ret,wlen,actlen);
else
ret = actlen != wlen ? -1 : 0;
/* an answer is expected, and no error before */
if (!ret && rbuf && rlen) {
ret = usb_bulk_msg(dib->udev,usb_rcvbulkpipe(dib->udev,
dib->dibdev->dev_cl->pipe_cmd),rbuf,rlen,&actlen,
DIBUSB_I2C_TIMEOUT);
if (ret)
err("recv bulk message failed: %d",ret);
else {
deb_alot("rlen: %d\n",rlen);
debug_dump(rbuf,actlen);
}
}
up(&dib->usb_sem);
return ret;
}
/*
* Cypress controls
*/
int dibusb_write_usb(struct usb_dibusb *dib, u8 *buf, u16 len)
{
return dibusb_readwrite_usb(dib,buf,len,NULL,0);
}
#if 0
/*
* #if 0'ing the following functions as they are not in use _now_,
* but probably will be sometime.
*/
/*
* do not use this, just a workaround for a bug,
* which will hopefully never occur :).
*/
int dibusb_interrupt_read_loop(struct usb_dibusb *dib)
{
u8 b[1] = { DIBUSB_REQ_INTR_READ };
return dibusb_write_usb(dib,b,1);
}
#endif
/*
* ioctl for the firmware
*/
static int dibusb_ioctl_cmd(struct usb_dibusb *dib, u8 cmd, u8 *param, int plen)
{
u8 b[34];
int size = plen > 32 ? 32 : plen;
memset(b,0,34);
b[0] = DIBUSB_REQ_SET_IOCTL;
b[1] = cmd;
if (size > 0)
memcpy(&b[2],param,size);
return dibusb_write_usb(dib,b,34); //2+size);
}
/*
* ioctl for power control
*/
int dibusb_hw_wakeup(struct dvb_frontend *fe)
{
struct usb_dibusb *dib = (struct usb_dibusb *) fe->dvb->priv;
u8 b[1] = { DIBUSB_IOCTL_POWER_WAKEUP };
deb_info("dibusb-device is getting up.\n");
switch (dib->dibdev->dev_cl->id) {
case DTT200U:
break;
default:
dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
break;
}
if (dib->fe_init)
return dib->fe_init(fe);
return 0;
}
int dibusb_hw_sleep(struct dvb_frontend *fe)
{
struct usb_dibusb *dib = (struct usb_dibusb *) fe->dvb->priv;
u8 b[1] = { DIBUSB_IOCTL_POWER_SLEEP };
deb_info("dibusb-device is going to bed.\n");
/* workaround, something is wrong, when dibusb 1.1 device are going to bed too late */
switch (dib->dibdev->dev_cl->id) {
case DIBUSB1_1:
case NOVAT_USB2:
case DTT200U:
break;
default:
dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
break;
}
if (dib->fe_sleep)
return dib->fe_sleep(fe);
return 0;
}
int dibusb_set_streaming_mode(struct usb_dibusb *dib,u8 mode)
{
u8 b[2] = { DIBUSB_REQ_SET_STREAMING_MODE, mode };
return dibusb_readwrite_usb(dib,b,2,NULL,0);
}
static int dibusb_urb_kill(struct usb_dibusb *dib)
{
int i;
deb_info("trying to kill urbs\n");
if (dib->init_state & DIBUSB_STATE_URB_SUBMIT) {
for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) {
deb_info("killing URB no. %d.\n",i);
/* stop the URB */
usb_kill_urb(dib->urb_list[i]);
}
} else
deb_info(" URBs not killed.\n");
dib->init_state &= ~DIBUSB_STATE_URB_SUBMIT;
return 0;
}
static int dibusb_urb_submit(struct usb_dibusb *dib)
{
int i,ret;
if (dib->init_state & DIBUSB_STATE_URB_INIT) {
for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) {
deb_info("submitting URB no. %d\n",i);
if ((ret = usb_submit_urb(dib->urb_list[i],GFP_ATOMIC))) {
err("could not submit buffer urb no. %d - get them all back\n",i);
dibusb_urb_kill(dib);
return ret;
}
dib->init_state |= DIBUSB_STATE_URB_SUBMIT;
}
}
return 0;
}
int dibusb_streaming(struct usb_dibusb *dib,int onoff)
{
if (onoff)
dibusb_urb_submit(dib);
else
dibusb_urb_kill(dib);
switch (dib->dibdev->dev_cl->id) {
case DIBUSB2_0:
case DIBUSB2_0B:
case NOVAT_USB2:
case UMT2_0:
if (onoff)
return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_ENABLE_STREAM,NULL,0);
else
return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_DISABLE_STREAM,NULL,0);
break;
default:
break;
}
return 0;
}
int dibusb_urb_init(struct usb_dibusb *dib)
{
int i,bufsize,def_pid_parse = 1;
/*
* when reloading the driver w/o replugging the device
* a timeout occures, this helps
*/
usb_clear_halt(dib->udev,usb_sndbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_cmd));
usb_clear_halt(dib->udev,usb_rcvbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_cmd));
usb_clear_halt(dib->udev,usb_rcvbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_data));
/* allocate the array for the data transfer URBs */
dib->urb_list = kmalloc(dib->dibdev->dev_cl->urb_count*sizeof(struct urb *),GFP_KERNEL);
if (dib->urb_list == NULL)
return -ENOMEM;
memset(dib->urb_list,0,dib->dibdev->dev_cl->urb_count*sizeof(struct urb *));
dib->init_state |= DIBUSB_STATE_URB_LIST;
bufsize = dib->dibdev->dev_cl->urb_count*dib->dibdev->dev_cl->urb_buffer_size;
deb_info("allocate %d bytes as buffersize for all URBs\n",bufsize);
/* allocate the actual buffer for the URBs */
if ((dib->buffer = pci_alloc_consistent(NULL,bufsize,&dib->dma_handle)) == NULL) {
deb_info("not enough memory.\n");
return -ENOMEM;
}
deb_info("allocation complete\n");
memset(dib->buffer,0,bufsize);
dib->init_state |= DIBUSB_STATE_URB_BUF;
/* allocate and submit the URBs */
for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) {
if (!(dib->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC))) {
return -ENOMEM;
}
usb_fill_bulk_urb( dib->urb_list[i], dib->udev,
usb_rcvbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_data),
&dib->buffer[i*dib->dibdev->dev_cl->urb_buffer_size],
dib->dibdev->dev_cl->urb_buffer_size,
dibusb_urb_complete, dib);
dib->urb_list[i]->transfer_flags = 0;
dib->init_state |= DIBUSB_STATE_URB_INIT;
}
/* dib->pid_parse here contains the value of the module parameter */
/* decide if pid parsing can be deactivated:
* is possible (by device type) and wanted (by user)
*/
switch (dib->dibdev->dev_cl->id) {
case DIBUSB2_0:
case DIBUSB2_0B:
if (dib->udev->speed == USB_SPEED_HIGH && !dib->pid_parse) {
def_pid_parse = 0;
info("running at HIGH speed, will deliver the complete TS.");
} else
info("will use pid_parsing.");
break;
default:
break;
}
/* from here on it contains the device and user decision */
dib->pid_parse = def_pid_parse;
return 0;
}
int dibusb_urb_exit(struct usb_dibusb *dib)
{
int i;
dibusb_urb_kill(dib);
if (dib->init_state & DIBUSB_STATE_URB_LIST) {
for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) {
if (dib->urb_list[i] != NULL) {
deb_info("freeing URB no. %d.\n",i);
/* free the URBs */
usb_free_urb(dib->urb_list[i]);
}
}
/* free the urb array */
kfree(dib->urb_list);
dib->init_state &= ~DIBUSB_STATE_URB_LIST;
}
if (dib->init_state & DIBUSB_STATE_URB_BUF)
pci_free_consistent(NULL,
dib->dibdev->dev_cl->urb_buffer_size*dib->dibdev->dev_cl->urb_count,
dib->buffer,dib->dma_handle);
dib->init_state &= ~DIBUSB_STATE_URB_BUF;
dib->init_state &= ~DIBUSB_STATE_URB_INIT;
return 0;
}
/*
* dvb-dibusb.h
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
* 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.
*
* for more information see dvb-dibusb-core.c .
*/
#ifndef __DVB_DIBUSB_H__
#define __DVB_DIBUSB_H__
#include <linux/input.h>
#include <linux/config.h>
#include <linux/usb.h>
#include "dvb_frontend.h"
#include "dvb_demux.h"
#include "dvb_net.h"
#include "dmxdev.h"
#include "dib3000.h"
#include "mt352.h"
/* debug */
#ifdef CONFIG_DVB_DIBCOM_DEBUG
#define dprintk(level,args...) \
do { if ((dvb_dibusb_debug & level)) { printk(args); } } while (0)
#define debug_dump(b,l) {\
int i; \
for (i = 0; i < l; i++) deb_xfer("%02x ", b[i]); \
deb_xfer("\n");\
}
#else
#define dprintk(args...)
#define debug_dump(b,l)
#endif
extern int dvb_dibusb_debug;
/* Version information */
#define DRIVER_VERSION "0.3"
#define DRIVER_DESC "DiBcom based USB Budget DVB-T device"
#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
#define deb_info(args...) dprintk(0x01,args)
#define deb_xfer(args...) dprintk(0x02,args)
#define deb_alot(args...) dprintk(0x04,args)
#define deb_ts(args...) dprintk(0x08,args)
#define deb_err(args...) dprintk(0x10,args)
#define deb_rc(args...) dprintk(0x20,args)
/* generic log methods - taken from usb.h */
#undef err
#define err(format, arg...) printk(KERN_ERR "dvb-dibusb: " format "\n" , ## arg)
#undef info
#define info(format, arg...) printk(KERN_INFO "dvb-dibusb: " format "\n" , ## arg)
#undef warn
#define warn(format, arg...) printk(KERN_WARNING "dvb-dibusb: " format "\n" , ## arg)
struct dibusb_usb_controller {
const char *name; /* name of the usb controller */
u16 cpu_cs_register; /* needs to be restarted, when the firmware has been downloaded. */
};
typedef enum {
DIBUSB1_1 = 0,
DIBUSB1_1_AN2235,
DIBUSB2_0,
UMT2_0,
DIBUSB2_0B,
NOVAT_USB2,
DTT200U,
} dibusb_class_t;
typedef enum {
DIBUSB_TUNER_CABLE_THOMSON = 0,
DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5,
DIBUSB_TUNER_CABLE_LG_TDTP_E102P,
DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5,
} dibusb_tuner_t;
typedef enum {
DIBUSB_DIB3000MB = 0,
DIBUSB_DIB3000MC,
DIBUSB_MT352,
DTT200U_FE,
} dibusb_demodulator_t;
typedef enum {
DIBUSB_RC_NO = 0,
DIBUSB_RC_NEC_PROTOCOL,
DIBUSB_RC_HAUPPAUGE_PROTO,
} dibusb_remote_t;
struct dibusb_tuner {
dibusb_tuner_t id;
u8 pll_addr; /* tuner i2c address */
};
extern struct dibusb_tuner dibusb_tuner[];
#define DIBUSB_POSSIBLE_I2C_ADDR_NUM 4
struct dibusb_demod {
dibusb_demodulator_t id;
int pid_filter_count; /* counter of the internal pid_filter */
u8 i2c_addrs[DIBUSB_POSSIBLE_I2C_ADDR_NUM]; /* list of possible i2c addresses of the demod */
};
#define DIBUSB_MAX_TUNER_NUM 2
struct dibusb_device_class {
dibusb_class_t id;
const struct dibusb_usb_controller *usb_ctrl; /* usb controller */
const char *firmware; /* valid firmware filenames */
int pipe_cmd; /* command pipe (read/write) */
int pipe_data; /* data pipe */
int urb_count; /* number of data URBs to be submitted */
int urb_buffer_size; /* the size of the buffer for each URB */
dibusb_remote_t remote_type; /* does this device have a ir-receiver */
struct dibusb_demod *demod; /* which demodulator is mount */
struct dibusb_tuner *tuner; /* which tuner can be found here */
};
#define DIBUSB_ID_MAX_NUM 15
struct dibusb_usb_device {
const char *name; /* real name of the box */
struct dibusb_device_class *dev_cl; /* which dibusb_device_class is this device part of */
struct usb_device_id *cold_ids[DIBUSB_ID_MAX_NUM]; /* list of USB ids when this device is at pre firmware state */
struct usb_device_id *warm_ids[DIBUSB_ID_MAX_NUM]; /* list of USB ids when this device is at post firmware state */
};
/* a PID for the pid_filter list, when in use */
struct dibusb_pid
{
int index;
u16 pid;
int active;
};
struct usb_dibusb {
/* usb */
struct usb_device * udev;
struct dibusb_usb_device * dibdev;
#define DIBUSB_STATE_INIT 0x000
#define DIBUSB_STATE_URB_LIST 0x001
#define DIBUSB_STATE_URB_BUF 0x002
#define DIBUSB_STATE_URB_INIT 0x004
#define DIBUSB_STATE_DVB 0x008
#define DIBUSB_STATE_I2C 0x010
#define DIBUSB_STATE_REMOTE 0x020
#define DIBUSB_STATE_URB_SUBMIT 0x040
int init_state;
int feedcount;
struct dib_fe_xfer_ops xfer_ops;
struct dibusb_tuner *tuner;
struct urb **urb_list;
u8 *buffer;
dma_addr_t dma_handle;
/* I2C */
struct i2c_adapter i2c_adap;
/* locking */
struct semaphore usb_sem;
struct semaphore i2c_sem;
/* dvb */
struct dvb_adapter adapter;
struct dmxdev dmxdev;
struct dvb_demux demux;
struct dvb_net dvb_net;
struct dvb_frontend* fe;
int (*fe_sleep) (struct dvb_frontend *);
int (*fe_init) (struct dvb_frontend *);
/* remote control */
struct input_dev rc_input_dev;
struct work_struct rc_query_work;
int last_event;
int last_state; /* for Hauppauge RC protocol */
int repeat_key_count;
int rc_key_repeat_count; /* module parameter */
/* module parameters */
int pid_parse;
int rc_query_interval;
};
/* commonly used functions in the separated files */
/* dvb-dibusb-firmware.c */
int dibusb_loadfirmware(struct usb_device *udev, struct dibusb_usb_device *dibdev);
/* dvb-dibusb-remote.c */
int dibusb_remote_exit(struct usb_dibusb *dib);
int dibusb_remote_init(struct usb_dibusb *dib);
/* dvb-dibusb-fe-i2c.c */
int dibusb_fe_init(struct usb_dibusb* dib);
int dibusb_fe_exit(struct usb_dibusb *dib);
int dibusb_i2c_init(struct usb_dibusb *dib);
int dibusb_i2c_exit(struct usb_dibusb *dib);
/* dvb-dibusb-dvb.c */
void dibusb_urb_complete(struct urb *urb, struct pt_regs *ptregs);
int dibusb_dvb_init(struct usb_dibusb *dib);
int dibusb_dvb_exit(struct usb_dibusb *dib);
/* dvb-dibusb-usb.c */
int dibusb_readwrite_usb(struct usb_dibusb *dib, u8 *wbuf, u16 wlen, u8 *rbuf,
u16 rlen);
int dibusb_write_usb(struct usb_dibusb *dib, u8 *buf, u16 len);
int dibusb_hw_wakeup(struct dvb_frontend *);
int dibusb_hw_sleep(struct dvb_frontend *);
int dibusb_set_streaming_mode(struct usb_dibusb *,u8);
int dibusb_streaming(struct usb_dibusb *,int);
int dibusb_urb_init(struct usb_dibusb *);
int dibusb_urb_exit(struct usb_dibusb *);
/* dvb-fe-dtt200u.c */
struct dvb_frontend* dtt200u_fe_attach(struct usb_dibusb *,struct dib_fe_xfer_ops *);
/* i2c and transfer stuff */
#define DIBUSB_I2C_TIMEOUT 5000
/*
* protocol of all dibusb related devices
*/
/*
* bulk msg to/from endpoint 0x01
*
* general structure:
* request_byte parameter_bytes
*/
#define DIBUSB_REQ_START_READ 0x00
#define DIBUSB_REQ_START_DEMOD 0x01
/*
* i2c read
* bulk write: 0x02 ((7bit i2c_addr << 1) & 0x01) register_bytes length_word
* bulk read: byte_buffer (length_word bytes)
*/
#define DIBUSB_REQ_I2C_READ 0x02
/*
* i2c write
* bulk write: 0x03 (7bit i2c_addr << 1) register_bytes value_bytes
*/
#define DIBUSB_REQ_I2C_WRITE 0x03
/*
* polling the value of the remote control
* bulk write: 0x04
* bulk read: byte_buffer (5 bytes)
*
* first byte of byte_buffer shows the status (0x00, 0x01, 0x02)
*/
#define DIBUSB_REQ_POLL_REMOTE 0x04
#define DIBUSB_RC_NEC_EMPTY 0x00
#define DIBUSB_RC_NEC_KEY_PRESSED 0x01
#define DIBUSB_RC_NEC_KEY_REPEATED 0x02
/* additional status values for Hauppauge Remote Control Protocol */
#define DIBUSB_RC_HAUPPAUGE_KEY_PRESSED 0x01
#define DIBUSB_RC_HAUPPAUGE_KEY_EMPTY 0x03
/* streaming mode:
* bulk write: 0x05 mode_byte
*
* mode_byte is mostly 0x00
*/
#define DIBUSB_REQ_SET_STREAMING_MODE 0x05
/* interrupt the internal read loop, when blocking */
#define DIBUSB_REQ_INTR_READ 0x06
/* io control
* 0x07 cmd_byte param_bytes
*
* param_bytes can be up to 32 bytes
*
* cmd_byte function parameter name
* 0x00 power mode
* 0x00 sleep
* 0x01 wakeup
*
* 0x01 enable streaming
* 0x02 disable streaming
*
*
*/
#define DIBUSB_REQ_SET_IOCTL 0x07
/* IOCTL commands */
/* change the power mode in firmware */
#define DIBUSB_IOCTL_CMD_POWER_MODE 0x00
#define DIBUSB_IOCTL_POWER_SLEEP 0x00
#define DIBUSB_IOCTL_POWER_WAKEUP 0x01
/* modify streaming of the FX2 */
#define DIBUSB_IOCTL_CMD_ENABLE_STREAM 0x01
#define DIBUSB_IOCTL_CMD_DISABLE_STREAM 0x02
#endif
/*
* dvb-dtt200u-fe.c is a driver which implements the frontend-part of the
* Yakumo/Typhoon/Hama USB2.0 boxes. It is hard-wired to the dibusb-driver as
* it uses the usb-transfer functions directly (maybe creating a
* generic-dvb-usb-lib for all usb-drivers will be reduce some more code.)
*
* Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@desy.de>
*
* see dvb-dibusb-core.c for copyright details.
*/
/* guessed protocol description (reverse engineered):
* read
* 00 - USB type 0x02 for usb2.0, 0x01 for usb1.1
* 81 - <TS_LOCK> <current frequency divided by 250000>
* 82 - crash - do not touch
* 83 - crash - do not touch
* 84 - remote control
* 85 - crash - do not touch (OK, stop testing here)
* 88 - locking 2 bytes (0x80 0x40 == no signal, 0x89 0x20 == nice signal)
* 89 - noise-to-signal
* 8a - unkown 1 byte - signal_strength
* 8c - ber ???
* 8d - ber
* 8e - unc
*
* write
* 02 - bandwidth
* 03 - frequency (divided by 250000)
* 04 - pid table (index pid(7:0) pid(12:8))
* 05 - reset the pid table
* 08 - demod transfer enabled or not (FX2 transfer is enabled by default)
*/
#include "dvb-dibusb.h"
#include "dvb_frontend.h"
struct dtt200u_fe_state {
struct usb_dibusb *dib;
struct dvb_frontend_parameters fep;
struct dvb_frontend frontend;
};
#define moan(which,what) info("unexpected value in '%s' for cmd '%02x' - please report to linux-dvb@linuxtv.org",which,what)
static int dtt200u_fe_read_status(struct dvb_frontend* fe, fe_status_t *stat)
{
struct dtt200u_fe_state *state = fe->demodulator_priv;
u8 bw[1] = { 0x81 };
u8 br[3] = { 0 };
// u8 bdeb[5] = { 0 };
dibusb_readwrite_usb(state->dib,bw,1,br,3);
switch (br[0]) {
case 0x01:
*stat = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
break;
case 0x00:
*stat = 0;
break;
default:
moan("br[0]",0x81);
break;
}
// bw[0] = 0x88;
// dibusb_readwrite_usb(state->dib,bw,1,bdeb,5);
// deb_info("%02x: %02x %02x %02x %02x %02x\n",bw[0],bdeb[0],bdeb[1],bdeb[2],bdeb[3],bdeb[4]);
return 0;
}
static int dtt200u_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
{
struct dtt200u_fe_state *state = fe->demodulator_priv;
u8 bw[1] = { 0x8d };
*ber = 0;
dibusb_readwrite_usb(state->dib,bw,1,(u8*) ber, 3);
return 0;
}
static int dtt200u_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
{
struct dtt200u_fe_state *state = fe->demodulator_priv;
u8 bw[1] = { 0x8c };
*unc = 0;
dibusb_readwrite_usb(state->dib,bw,1,(u8*) unc, 3);
return 0;
}
static int dtt200u_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
{
struct dtt200u_fe_state *state = fe->demodulator_priv;
u8 bw[1] = { 0x8a };
u8 b;
dibusb_readwrite_usb(state->dib,bw,1,&b, 1);
*strength = (b << 8) | b;
return 0;
}
static int dtt200u_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
{
struct dtt200u_fe_state *state = fe->demodulator_priv;
u8 bw[1] = { 0x89 };
u8 br[1] = { 0 };
dibusb_readwrite_usb(state->dib,bw,1,br,1);
*snr = ((0xff - br[0]) << 8) | (0xff - br[0]);
return 0;
}
static int dtt200u_fe_init(struct dvb_frontend* fe)
{
struct dtt200u_fe_state *state = fe->demodulator_priv;
u8 b[] = { 0x01 };
return dibusb_write_usb(state->dib,b,1);
}
static int dtt200u_fe_sleep(struct dvb_frontend* fe)
{
return dtt200u_fe_init(fe);
}
static int dtt200u_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
{
tune->min_delay_ms = 1500;
tune->step_size = 166667;
tune->max_drift = 166667 * 2;
return 0;
}
static int dtt200u_fe_set_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep)
{
struct dtt200u_fe_state *state = fe->demodulator_priv;
u16 freq = fep->frequency / 250000;
u8 bw,bwbuf[2] = { 0x03, 0 }, freqbuf[3] = { 0x02, 0, 0 };
switch (fep->u.ofdm.bandwidth) {
case BANDWIDTH_8_MHZ: bw = 8; break;
case BANDWIDTH_7_MHZ: bw = 7; break;
case BANDWIDTH_6_MHZ: bw = 6; break;
case BANDWIDTH_AUTO: return -EOPNOTSUPP;
default:
return -EINVAL;
}
deb_info("set_frontend\n");
bwbuf[1] = bw;
dibusb_write_usb(state->dib,bwbuf,2);
freqbuf[1] = freq & 0xff;
freqbuf[2] = (freq >> 8) & 0xff;
dibusb_write_usb(state->dib,freqbuf,3);
memcpy(&state->fep,fep,sizeof(struct dvb_frontend_parameters));
return 0;
}
static int dtt200u_fe_get_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep)
{
struct dtt200u_fe_state *state = fe->demodulator_priv;
memcpy(fep,&state->fep,sizeof(struct dvb_frontend_parameters));
return 0;
}
static void dtt200u_fe_release(struct dvb_frontend* fe)
{
struct dtt200u_fe_state *state = (struct dtt200u_fe_state*) fe->demodulator_priv;
kfree(state);
}
static int dtt200u_pid_control(struct dvb_frontend *fe,int index, int pid,int onoff)
{
struct dtt200u_fe_state *state = (struct dtt200u_fe_state*) fe->demodulator_priv;
u8 b_pid[4];
pid = onoff ? pid : 0;
b_pid[0] = 0x04;
b_pid[1] = index;
b_pid[2] = pid & 0xff;
b_pid[3] = (pid >> 8) & 0xff;
dibusb_write_usb(state->dib,b_pid,4);
return 0;
}
static int dtt200u_fifo_control(struct dvb_frontend *fe, int onoff)
{
struct dtt200u_fe_state *state = (struct dtt200u_fe_state*) fe->demodulator_priv;
u8 b_streaming[2] = { 0x08, onoff };
u8 b_rst_pid[1] = { 0x05 };
dibusb_write_usb(state->dib,b_streaming,2);
if (!onoff)
dibusb_write_usb(state->dib,b_rst_pid,1);
return 0;
}
static struct dvb_frontend_ops dtt200u_fe_ops;
struct dvb_frontend* dtt200u_fe_attach(struct usb_dibusb *dib, struct dib_fe_xfer_ops *xfer_ops)
{
struct dtt200u_fe_state* state = NULL;
/* allocate memory for the internal state */
state = (struct dtt200u_fe_state*) kmalloc(sizeof(struct dtt200u_fe_state), GFP_KERNEL);
if (state == NULL)
goto error;
memset(state,0,sizeof(struct dtt200u_fe_state));
deb_info("attaching frontend dtt200u\n");
state->dib = dib;
state->frontend.ops = &dtt200u_fe_ops;
state->frontend.demodulator_priv = state;
xfer_ops->fifo_ctrl = dtt200u_fifo_control;
xfer_ops->pid_ctrl = dtt200u_pid_control;
goto success;
error:
return NULL;
success:
return &state->frontend;
}
static struct dvb_frontend_ops dtt200u_fe_ops = {
.info = {
.name = "DTT200U (Yakumo/Typhoon/Hama) DVB-T",
.type = FE_OFDM,
.frequency_min = 44250000,
.frequency_max = 867250000,
.frequency_stepsize = 250000,
.caps = FE_CAN_INVERSION_AUTO |
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
FE_CAN_TRANSMISSION_MODE_AUTO |
FE_CAN_GUARD_INTERVAL_AUTO |
FE_CAN_RECOVER |
FE_CAN_HIERARCHY_AUTO,
},
.release = dtt200u_fe_release,
.init = dtt200u_fe_init,
.sleep = dtt200u_fe_sleep,
.set_frontend = dtt200u_fe_set_frontend,
.get_frontend = dtt200u_fe_get_frontend,
.get_tune_settings = dtt200u_fe_get_tune_settings,
.read_status = dtt200u_fe_read_status,
.read_ber = dtt200u_fe_read_ber,
.read_signal_strength = dtt200u_fe_read_signal_strength,
.read_snr = dtt200u_fe_read_snr,
.read_ucblocks = dtt200u_fe_read_unc_blocks,
};
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