Hi
I've been using the driver posted in
http://linuxtv.org/wiki/index.php/Pinnacle_PCTV_200e a few years, but
it didn't compile with the last git repository, so i've made a few
changes:
* Change "adap->fe" to "adap->fe_adap[0].fe"
* Change "adap->priv" to "adap->fe_adap[0].priv"
* Change "dvb_usb_device_properties" initialization to include
"{ .num_frontends = 1, .fe = {{"
Making this changes, the drivers works perfectly.
I think it would be useful to update the linuxtv page with this
changes. I've attached the file.
Thanks
Sergio
/*
* DVB USB compliant linux driver for Pinnacle PCTV 200e DVB-T reciever
*
* Copyright (C) 2007 Jakob Steidl ([email protected])
* based on Patrick Boettcher's driver for the Nebula Electronics uDigiTV
*
*
* 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.
*
* see Documentation/dvb/README.dvb-usb for more information
*/
// mt352 registers
#define CLOCK_CTL 0x89
#define RESET 0x50
#define ACQ_CTL 0x53
#define TRL_NOMINAL_RATE_1 0x54
#define INPUT_FREQ_1 0x56
#define UNKNOWN_3 0x5e
#define AGC_TARGET 0x67
#define CAPT_RANGE 0x75
#define SNR_SELECT_1 0x79
#define UNKNOWN_1 0x7B
#define SCAN_CTL 0x88
#define MCLK_RATIO 0x8B
#define GPP_CTL 0x8C
#define ADC_CTL_1 0x8E
#define UNKNOWN_2 0x98
#include "pctv200e.h"
#include "dvb-usb.h"
#include "mt352.h"
#include "mt2060.h"
#include "mt2060_priv.h"
/* debug */
// To enable the debug set a value 1 for dvb_usb_pctv200e_debug
int dvb_usb_pctv200e_debug=0;
static int ctrl_msg_last_device=0;
static int ctrl_msg_last_operation=0;
static struct mt352_config pctv200e_mt352_config;
static struct mt2060_config pctv200e_mt2060_config;
module_param_named(debug,dvb_usb_pctv200e_debug, int, 0644);
MODULE_PARM_DESC( debug, "Set debug level (1=info,xfer=2,rc=4 (RC is the codeword for ALL ;) (|-able))." DVB_USB_DEBUG_STATUS );
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
/* I2C */
/*
01 c0 02 03 80
- request type (read: 0x01, write: 0x02)
- addr to be read or written (0xc0 ... tuner)
- number of of bits that follow
- just data
- data (optional, if number data >1)
*/
static int pctv200e_ctrl_msg(struct dvb_usb_device *d,
u8 addr, u8 rw, u8 reg, u8 *wbuf, int wlen, u8 *rbuf,int rlen)
{
// atm, u8 rw is being ignored, it should be clear from the
int wo = (rbuf == NULL || rlen == 0); /* then its a write-only*/
int counter;
u8 sndbuf[5],rcvbuf[64] = { 0 };
// u8 sndbuf[8],rcvbuf[5]; /* actually we don't know the max. answer lenght //yet..
if (wlen>64) {
warn ("pctv200e_ctrl_msg: failed, command too long!");
return 0;
}
memset(sndbuf,0,5); memset(rcvbuf,0,64);
if (ctrl_msg_last_device == 0) {
// The very first time we send the following sequence "0x15 0x80" and then "0x16 0x00"
sndbuf[0] = 0x15;
sndbuf[1] = 0x80;
dvb_usb_generic_rw(d,sndbuf,2,rcvbuf,64,4);
if (dvb_usb_pctv200e_debug) {
warn("crtl_msg() wlen: %d, rlen: %d, READ: %x %x %x %x %x",wlen,rlen,sndbuf[0],sndbuf[1],sndbuf[2],sndbuf[3],sndbuf[4]);
warn("crtl_msg() RECEIVED: %x %x %x %x %x %x %x %x %x %x %x %x %x",rcvbuf[0],rcvbuf[1],rcvbuf[2],rcvbuf[3],rcvbuf[4],rcvbuf[5],rcvbuf[6],rcvbuf[7],rcvbuf[8],rcvbuf[9],rcvbuf[10],rcvbuf[11],rcvbuf[12]);
sndbuf[0] = 0x16;
sndbuf[1] = 0x00;
dvb_usb_generic_rw(d,sndbuf,2,rcvbuf,64,4);
warn("crtl_msg() wlen: %d, rlen: %d, READ: %x %x %x %x %x",wlen,rlen,sndbuf[0],sndbuf[1],sndbuf[2],sndbuf[3],sndbuf[4]);
warn("crtl_msg() RECEIVED: %x %x %x %x %x %x %x %x %x %x %x %x %x",rcvbuf[0],rcvbuf[1],rcvbuf[2],rcvbuf[3],rcvbuf[4],rcvbuf[5],rcvbuf[6],rcvbuf[7],rcvbuf[8],rcvbuf[9],rcvbuf[10],rcvbuf[11],rcvbuf[12]);
}
}
// Now start to check the last operation and send the intermedium sequence
// If the command is sent to the tuner mt2060
// first we sent the sequence "0x16 0x01", and below after the command
// then we send the sequence "0x16 0x00".
// This is not needed when the command goes to the demod mt352
if (addr == pctv200e_mt2060_config.i2c_address ) {
sndbuf[0] = 0x16;
sndbuf[1] = 0x01;
dvb_usb_generic_rw(d,sndbuf,2,rcvbuf,64,4);
if (dvb_usb_pctv200e_debug) {
warn("crtl_msg() wlen: %d, rlen: %d, READ: %x %x %x %x %x",wlen,rlen,sndbuf[0],sndbuf[1],sndbuf[2],sndbuf[3],sndbuf[4]);
warn("crtl_msg() RECEIVED: %x %x %x %x %x %x %x %x %x %x %x %x %x",rcvbuf[0],rcvbuf[1],rcvbuf[2],rcvbuf[3],rcvbuf[4],rcvbuf[5],rcvbuf[6],rcvbuf[7],rcvbuf[8],rcvbuf[9],rcvbuf[10],rcvbuf[11],rcvbuf[12]);
}
}
sndbuf[1] = addr;
ctrl_msg_last_device = addr;
// We store who which address was access (DEMOD or TUNER)
// memcpy(&sndbuf[5],wbuf,wlen);
if (wo) {
ctrl_msg_last_operation = 0x01;
sndbuf[0] = 0x01;
sndbuf[2] = 0x02;
sndbuf[3] = reg;
// We convert multiple writes into single writes
for (counter=0; counter < wlen; counter++) {
sndbuf[4] = wbuf[counter];
// For Pinnacle cards it should be send 0xf4 for ACQ_CTL as mentioned
// in mt352.c. At this moment the mt352.c send by default 0x50,
// so we intercept and change the value here.
// This way we don't need to change mt352.c
if ((addr == 0x3e) & (sndbuf[3] == ACQ_CTL) & (sndbuf[4] == 0x50)) {
if (dvb_usb_pctv200e_debug)
warn("crtl_msg(): Changed ACQ_CTL calue to 0xf4!!!");
sndbuf[4] = 0xf4;
}
// memcpy(&sndbuf[3],wbuf,wlen);
if (dvb_usb_pctv200e_debug) {
warn("crtl_msg() wlen: %d, rlen: %d,WRITE: %x %x %x %x %x",wlen,rlen,sndbuf[0],sndbuf[1],sndbuf[2],sndbuf[3],sndbuf[4]);
}
dvb_usb_generic_rw(d,sndbuf,5,rcvbuf,64,4);
if (dvb_usb_pctv200e_debug) {
warn("crtl_msg() RECEIVED: %x %x %x %x %x %x %x %x %x %x %x %x %x",rcvbuf[0],rcvbuf[1],rcvbuf[2],rcvbuf[3],rcvbuf[4],rcvbuf[5],rcvbuf[6],rcvbuf[7],rcvbuf[8],rcvbuf[9],rcvbuf[10],rcvbuf[11],rcvbuf[12]);
}
if (rcvbuf[0] != 0x1) {
warn("crtl_msg() WRITE ERROR: returned byte [0] not 0x1");
// return -EIO;
}
if (rcvbuf[1] != 0x0) {
warn("crtl_msg() WRITE ERROR: returned error!");
// return -EIO;
}
// it is write_regs, so we increment the register value
sndbuf[3] = sndbuf[3]+1;
}
} else {
ctrl_msg_last_operation = 0x02;
sndbuf[0] = 0x02;
sndbuf[2] = 0x01;
sndbuf[3] = 0x01;
sndbuf[4] = reg;
if (dvb_usb_pctv200e_debug) {
warn("crtl_msg() wlen: %d, rlen: %d, READ: %x %x %x %x %x",wlen,rlen,sndbuf[0],sndbuf[1],sndbuf[2],sndbuf[3],sndbuf[4]);
}
dvb_usb_generic_rw(d,sndbuf,5,rcvbuf,64,4);
if (rlen > 0) {
memcpy(rbuf,&rcvbuf[2],rlen);
}
if (dvb_usb_pctv200e_debug) {
warn("crtl_msg() RECEIVED: %x %x %x %x %x %x %x %x %x %x %x %x %x",rcvbuf[0],rcvbuf[1],rcvbuf[2],rcvbuf[3],rcvbuf[4],rcvbuf[5],rcvbuf[6],rcvbuf[7],rcvbuf[8],rcvbuf[9],rcvbuf[10],rcvbuf[11],rcvbuf[12]);
}
}
if (addr == pctv200e_mt2060_config.i2c_address ) {
sndbuf[0] = 0x16;
sndbuf[1] = 0x00;
dvb_usb_generic_rw(d,sndbuf,2,rcvbuf,64,4);
if (dvb_usb_pctv200e_debug) {
warn("crtl_msg() wlen: %d, rlen: %d, READ: %x %x %x %x %x",wlen,rlen,sndbuf[0],sndbuf[1],sndbuf[2],sndbuf[3],sndbuf[4]);
warn("crtl_msg() RECEIVED: %x %x %x %x %x %x %x %x %x %x %x %x %x",rcvbuf[0],rcvbuf[1],rcvbuf[2],rcvbuf[3],rcvbuf[4],rcvbuf[5],rcvbuf[6],rcvbuf[7],rcvbuf[8],rcvbuf[9],rcvbuf[10],rcvbuf[11],rcvbuf[12]);
}
}
return 0;
}
static int pctv200e_cmd_msg(struct dvb_usb_device *d, u8 *wbuf, int wlen)
{
u8 sndbuf[64] = { 0 };
u8 rcvbuf[64] = { 0 };
// u8 sndbuf[8],rcvbuf[5]; /* actually we don't know the max. answer lenght //yet.. */
if (wlen>64) {
warn ("pctv200e_cmd_msg: failed, command too long!");
return 0;
}
memset(sndbuf,0,64); memset(rcvbuf,0,64);
memcpy(sndbuf,wbuf,wlen);
if (dvb_usb_pctv200e_debug)
warn("cmd_msg() wlen: %d, WRITE: %x %x %x %x %x",wlen,sndbuf[0],sndbuf[1],sndbuf[2],sndbuf[3],sndbuf[4]);
dvb_usb_generic_rw(d,sndbuf,wlen,rcvbuf,64,4);
if (rcvbuf[1] != 0x00) {
warn("crtl_msg() WRITE ERROR: returned error!");
}
if (dvb_usb_pctv200e_debug)
warn("cmd_msg() RECEIVED: %x %x %x %x %x %x %x %x %x %x %x %x %x",rcvbuf[0],rcvbuf[1],rcvbuf[2],rcvbuf[3],rcvbuf[4],rcvbuf[5],rcvbuf[6],rcvbuf[7],rcvbuf[8],rcvbuf[9],rcvbuf[10],rcvbuf[11],rcvbuf[12]);
return 0;
}
static int pctv200e_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
int i;
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
return -EAGAIN;
if (num > 2)
warn("more than 2 i2c messages at a time is not handled yet. TODO.");
for (i = 0; i < num; i++) {
/* write/read request */
if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
if (pctv200e_ctrl_msg(d, msg[i].addr,USB_READ, msg[i].buf[0], NULL, 0, msg[i+1].buf,msg[i+1].len) < 0)
break;
i++;
} else
if (pctv200e_ctrl_msg(d,msg[i].addr,USB_WRITE, msg[i].buf[0],&msg[i].buf[1],msg[i].len-1,NULL,0) < 0)
break;
}
mutex_unlock(&d->i2c_mutex);
if (dvb_usb_pctv200e_debug)
warn("pctv200e_i2c_xfer() called.");
return i;
}
static u32 pctv200e_i2c_func(struct i2c_adapter *adapter)
{
warn ("pctv200e_i2c_func: entering, done nothing");
return I2C_FUNC_I2C;
}
static struct i2c_algorithm pctv200e_i2c_algo = {
.master_xfer = pctv200e_i2c_xfer,
.functionality = pctv200e_i2c_func,
};
/* Callbacks for DVB USB */
static int pctv200e_identify_state (struct usb_device *udev, struct
dvb_usb_device_properties *props, struct dvb_usb_device_description **desc,
int *cold)
{
*cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0;
return 0;
}
// probably this needs to be changed.
static int pctv200e_mt352_demod_init(struct dvb_frontend *fe)
{
// We implement the RESET sequence for the demod mt352
static u8 clock_config [] = { CLOCK_CTL, 0xbd, 0x28 };
static u8 reset [] = { RESET, 0x80 };
static u8 reset_stop [] = { RESET, 0x00 };
static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
static u8 agc_cfg [] = { AGC_TARGET, 0x1c };
// static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 };
static u8 capt_range_cfg[] = { CAPT_RANGE, 0x30 };
static u8 input_freq[] = { INPUT_FREQ_1, 0x31, 0xb5 };
static u8 clock_ratio[] = { MCLK_RATIO, 0x00 };
static u8 scan_ctl[] = { SCAN_CTL, 0x0d };
static u8 unknown_1[] = { UNKNOWN_1, 0x04 };
static u8 acq_ctl[] = { ACQ_CTL, 0xf4 };
static u8 trl_nominal_rate[] = { TRL_NOMINAL_RATE_1, 0x73, 0x1c };
static u8 unknown_2[] = { UNKNOWN_2, 0x00, 0x00, 0x80, 0x20, 0x80, 0x80, 0x55, 0x62, 0x00 };
static u8 unknown_3[] = { UNKNOWN_3, 0x01 };
// static u8 snr_select_1[] = { SNR_SELECT_1, 0x20, 0x00 };
mt352_write(fe, clock_config, sizeof(clock_config));
udelay(1000);
mt352_write(fe, reset, sizeof(reset));
mt352_write(fe, reset_stop, sizeof(reset_stop));
mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
mt352_write(fe, input_freq, sizeof(input_freq));
mt352_write(fe, clock_ratio, sizeof(clock_ratio));
mt352_write(fe, scan_ctl, sizeof(scan_ctl));
mt352_write(fe, unknown_1, sizeof(unknown_1));
mt352_write(fe, acq_ctl, sizeof(acq_ctl));
mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
mt352_write(fe, agc_cfg, sizeof(agc_cfg));
mt352_write(fe, trl_nominal_rate, sizeof(trl_nominal_rate));
mt352_write(fe, unknown_2, sizeof(unknown_2));
mt352_write(fe, unknown_3, sizeof(unknown_3));
// mt352_write(fe, snr_select_1, sizeof(snr_select_1));
// mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg));
warn ("PCTV200e initialized mt352");
return 0;
}
static struct mt352_config pctv200e_mt352_config = {
.demod_address = 0x3e,
.demod_init = pctv200e_mt352_demod_init,
.no_tuner = 1,
.adc_clock = 20333,
.if2 = 56468,
};
static struct mt2060_config pctv200e_mt2060_config = {
.i2c_address = 0xc0,
.clock_out = 1,
};
static int pctv200e_mt2060_tuner_set_params (struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
{
struct dvb_usb_adapter *adap = fe->dvb->priv;
struct pctv200e_adapter_state *state = adap->fe_adap[0].priv;
warn ("pctv200e_mt2060_tuner_set_params: setting parameters!");
// ops->tuner_ops.set_params (ops,fep);
if (state == NULL) warn ("Juan: STATE pointer is NULL!!!!");
return state->set_param_save(fe, fep);
}
static u16 if1 = 1220; // this is probably wrong, but we need some value to compile this shite
// source (for the tuner attach: dibusb-common.c)
static int pctv200e_frontend_attach (struct dvb_usb_adapter *adap)
{
static u8 cmd_buf3[] = { 0x10, 0xED};
static u8 cmd_buf4[] = { 0x11, 0x41};
static u8 cmd_buf5[] = { 0x12, 0x01};
// Sending "0x18 0x01" turns the antenna power on
// Sending "0x18 0x00" turns the antenna power off
static u8 cmd_buf6[] = { 0x18, 0x01};
if ((adap->fe_adap[0].fe = dvb_attach (mt352_attach, &pctv200e_mt352_config, &adap->dev->i2c_adap)) != NULL) {
// adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
warn("attaching and initializing mt352 frontend.");
// pctv200e_cmd_msg(adap->dev, cmd_buf1, sizeof(cmd_buf1));
pctv200e_mt352_demod_init (adap->fe_adap[0].fe);
// Send, maybe is start command?
// pctv200e_cmd_msg(adap->dev, cmd_buf1, sizeof(cmd_buf1));
// pctv200e_cmd_msg(adap->dev, cmd_buf2, sizeof(cmd_buf2));
pctv200e_cmd_msg (adap->dev, cmd_buf3, sizeof(cmd_buf3));
pctv200e_cmd_msg (adap->dev, cmd_buf4, sizeof(cmd_buf4));
pctv200e_cmd_msg (adap->dev, cmd_buf5, sizeof(cmd_buf5));
pctv200e_cmd_msg (adap->dev, cmd_buf6, sizeof(cmd_buf6));
// pctv200e_cmd_msg(adap->dev, cmd_buf1, sizeof(cmd_buf1));
warn ("mt352 frontend attached.");
return 0;
}
warn ("failed attaching frontend mt352.");
return -EIO;
}
static int pctv200e_tuner_attach (struct dvb_usb_adapter *adap)
{
struct pctv200e_adapter_state *st = adap->fe_adap[0].priv;
// adap->fe->ops.tuner_ops.fe = adap->fe;
// if ((adap->fe = dvb_attach(mt2060_attach, &adap->fe->ops.tuner_ops,
if ((dvb_attach(mt2060_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, &pctv200e_mt2060_config, if1)) != NULL) {
// adap->fe->ops.tuner_ops.fe = adap->fe;
// adap->fe->ops.tuner_ops.set_params = pctv200e_mt2060_tuner_set_params;
// adap->pll_addr = 0xc0;
// adap->pll_desc = &dvb_pll_tded4;
warn("tuner mt2060 attached.");
warn("tuner mt2060 set_params starting.");
st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
adap->fe_adap[0].fe->ops.tuner_ops.set_params = pctv200e_mt2060_tuner_set_params;
warn("tuner mt2060 set_params passed.");
return 0;
}
warn("failed attaching frontend_attach (mt2060)");
return -EIO;
}
// currently not aim of my mission
#if 0
static struct dvb_usb_rc_key pctv200e_rc_keys[] = {
{ 0x5f, 0x55, KEY_0 },
{ 0x6f, 0x55, KEY_1 },
{ 0x9f, 0x55, KEY_2 },
{ 0xaf, 0x55, KEY_3 },
{ 0x5f, 0x56, KEY_4 },
{ 0x6f, 0x56, KEY_5 },
{ 0x9f, 0x56, KEY_6 },
{ 0xaf, 0x56, KEY_7 },
{ 0x5f, 0x59, KEY_8 },
{ 0x6f, 0x59, KEY_9 },
{ 0x9f, 0x59, KEY_TV },
{ 0xaf, 0x59, KEY_AUX },
{ 0x5f, 0x5a, KEY_DVD },
{ 0x6f, 0x5a, KEY_POWER },
{ 0x9f, 0x5a, KEY_MHP }, /* labelled 'Picture' */
{ 0xaf, 0x5a, KEY_AUDIO },
{ 0x5f, 0x65, KEY_INFO },
{ 0x6f, 0x65, KEY_F13 }, /* 16:9 */
{ 0x9f, 0x65, KEY_F14 }, /* 14:9 */
{ 0xaf, 0x65, KEY_EPG },
{ 0x5f, 0x66, KEY_EXIT },
{ 0x6f, 0x66, KEY_MENU },
{ 0x9f, 0x66, KEY_UP },
{ 0xaf, 0x66, KEY_DOWN },
{ 0x5f, 0x69, KEY_LEFT },
{ 0x6f, 0x69, KEY_RIGHT },
{ 0x9f, 0x69, KEY_ENTER },
{ 0xaf, 0x69, KEY_CHANNELUP },
{ 0x5f, 0x6a, KEY_CHANNELDOWN },
{ 0x6f, 0x6a, KEY_VOLUMEUP },
{ 0x9f, 0x6a, KEY_VOLUMEDOWN },
{ 0xaf, 0x6a, KEY_RED },
{ 0x5f, 0x95, KEY_GREEN },
{ 0x6f, 0x95, KEY_YELLOW },
{ 0x9f, 0x95, KEY_BLUE },
{ 0xaf, 0x95, KEY_SUBTITLE },
{ 0x5f, 0x96, KEY_F15 }, /* AD */
{ 0x6f, 0x96, KEY_TEXT },
{ 0x9f, 0x96, KEY_MUTE },
{ 0xaf, 0x96, KEY_REWIND },
{ 0x5f, 0x99, KEY_STOP },
{ 0x6f, 0x99, KEY_PLAY },
{ 0x9f, 0x99, KEY_FASTFORWARD },
{ 0xaf, 0x99, KEY_F16 }, /* chapter */
{ 0x5f, 0x9a, KEY_PAUSE },
{ 0x6f, 0x9a, KEY_PLAY },
{ 0x9f, 0x9a, KEY_RECORD },
{ 0xaf, 0x9a, KEY_F17 }, /* picture in picture */
{ 0x5f, 0xa5, KEY_KPPLUS }, /* zoom in */
{ 0x6f, 0xa5, KEY_KPMINUS }, /* zoom out */
{ 0x9f, 0xa5, KEY_F18 }, /* capture */
{ 0xaf, 0xa5, KEY_F19 }, /* web */
{ 0x5f, 0xa6, KEY_EMAIL },
{ 0x6f, 0xa6, KEY_PHONE },
{ 0x9f, 0xa6, KEY_PC },
};
static int pctv200e_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
int i;
u8 key[5];
u8 b[4] = { 0 };
*event = 0;
*state = REMOTE_NO_KEY_PRESSED;
pctv200e_ctrl_msg(d,USB_READ_REMOTE,0,NULL,0,&key[1],4);
/* Tell the device we've read the remote. Not sure how necessary
this is, but the Nebula SDK does it. */
pctv200e_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0);
/* if something is inside the buffer, simulate key press */
if (key[1] != 0)
{
for (i = 0; i < d->props.rc_key_map_size; i++) {
if (d->props.rc_key_map[i].custom == key[1] &&
d->props.rc_key_map[i].data == key[2]) {
*event = d->props.rc_key_map[i].event;
*state = REMOTE_KEY_PRESSED;
return 0;
}
}
}
if (key[0] != 0)
warn("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]);
return 0;
}
#endif
/* DVB USB Driver stuff */
static struct dvb_usb_device_properties pctv200e_properties;
static int pctv200e_probe (struct usb_interface *intf,
const struct usb_device_id *id)
{
struct dvb_usb_device *d;
int ret;
if ((ret = dvb_usb_device_init (intf, &pctv200e_properties, THIS_MODULE, &d, adapter_nr)) == 0) {
#if 0
u8 b[4] = { 0 };
/* do we need that?? */
if (d != NULL) { /* do that only when the firmware is loaded */
b[0] = 1;
pctv200e_ctrl_msg(d,USB_WRITE_REMOTE_TYPE,0,b,4,NULL,0);
b[0] = 0;
pctv200e_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0);
}
#endif
}
warn("usb_device_init sucessfull.");
return ret;
}
static struct usb_device_id pctv200e_table [] = {
{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_200E) },
{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_60E) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, pctv200e_table);
#define DIB0700_DEFAULT_DEVICE_PROPERTIES \
.size_of_priv = sizeof(struct dib0700_state)
static struct dvb_usb_device_properties pctv200e_properties = {
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING | DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = CYPRESS_FX2,
//.firmware = "dvb-usb-digitv-02.fw", // no!
.num_adapters = 1,
.adapter = {{
.num_frontends = 1,
.fe = {{
.frontend_attach = pctv200e_frontend_attach,
.tuner_attach = pctv200e_tuner_attach,
.size_of_priv = sizeof(struct pctv200e_adapter_state),
/* parameter for the MPEG2-data transfer */
.stream = {
.type = USB_BULK,
.count = 7,
.endpoint = 0x02,
.u = {
.bulk = {
.buffersize = 4096,
}
}
},
}},
}},
.identify_state = pctv200e_identify_state,
/*.rc_interval = 1000,
.rc_key_map = pctv200e_rc_keys,
.rc_key_map_size = ARRAY_SIZE(pctv200e_rc_keys),
.rc_query = pctv200e_rc_query,*/
.i2c_algo = &pctv200e_i2c_algo,
.generic_bulk_ctrl_endpoint = 0x01,
.num_device_descs = 2,
.devices = {
{ "Pinnacle PCTV 200e DVB-T",
{ &pctv200e_table[0], NULL },
{ NULL },
},
{ "Pinnacle PCTV 60e DVB-T",
{ &pctv200e_table[1], NULL },
{ NULL },
},
{ NULL },
}
};
static struct usb_driver pctv200e_driver = {
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
.owner = THIS_MODULE,
#endif
.name = "dvb_usb_pctv200e",
.probe = pctv200e_probe,
.disconnect = dvb_usb_device_exit,
.id_table = pctv200e_table,
};
/* module stuff */
static int __init pctv200e_module_init (void)
{
int result;
if ((result = usb_register(&pctv200e_driver))) {
err("usb_register failed. Error number %d",result);
return result;
}
warn("usb_register successfull.");
return 0;
}
static void __exit pctv200e_module_exit (void)
{
/* deregister this driver from the USB subsystem */
warn("usb_DEregister started.");
usb_deregister (&pctv200e_driver);
warn("usb_DEregister successfull.");
}
module_init (pctv200e_module_init);
module_exit (pctv200e_module_exit);
MODULE_AUTHOR("Jakob Steidl <[email protected]>");
MODULE_DESCRIPTION("Driver for Pinnacle PCTV 200e DVB-T USB2.0");
MODULE_VERSION("0.1");
MODULE_LICENSE("GPL");