Hello,
This is a stub patch to make the subjects card work.
I am using the driver on a pctv60e and it is very stable, I use it
daily. It should work for pctv200e but not owning the device I cannot
test it.
The code need to be cleaned, as I am not an experienced kernel coder.
The code in mt352.c contains an hard-coded address for the device, while
Pinnalce devices with that tuner uses a different address. Currently
the address is "hijacked" to be the correct one. This is a hack, and i
think that mt352.c should be changed to support multiple addresses,
selected via params, duplicate code or something.
Remote support is missing, cause it was not working out of the box. I
do not use it and so developing it for myself only was not very useful,
if someone wants it or is interested I can have a look.
The patch is generally messy, I need help there. I do not know if I
have to change all the functions to take as parameter an adapter_nr or
change the caller to continue to pass them a struct dvb_usb_device
obtained with i2c_get_adapdata(adapter_nr).
Here is the patch, as an attachment, thanks meanwhile.
Best Regards,
Gabriele Dini Ciacci
Signed-off-by: Gabriele Dini Ciacci <g...@diniciacci.org>
-----------
http://linux-wildo.sf.net
http://www.diniciacci.org
diff -uprN v4l-dvd/linux/drivers/media/dvb/dvb-usb/Kconfig my_v4l-dvb/linux/drivers/media/dvb/dvb-usb/Kconfig
--- v4l-dvd/linux/drivers/media/dvb/dvb-usb/Kconfig 2009-01-06 00:16:39.000000000 +0100
+++ my_v4l-dvb/linux/drivers/media/dvb/dvb-usb/Kconfig 2009-01-06 15:22:31.000000000 +0100
@@ -299,3 +299,9 @@ config DVB_USB_AF9015
select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMIZE
help
Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver
+
+config DVB_USB_PCTV200E
+ tristate "Pinnacle PCTV200e and PCTV60e support"
+ depends on DVB_USB && EXPERIMENTAL
+ help
+ Say Y here to support for PCTV200e or PCTV60e
diff -uprN v4l-dvd/linux/drivers/media/dvb/dvb-usb/Makefile my_v4l-dvb/linux/drivers/media/dvb/dvb-usb/Makefile
--- v4l-dvd/linux/drivers/media/dvb/dvb-usb/Makefile 2009-01-06 00:16:39.000000000 +0100
+++ my_v4l-dvb/linux/drivers/media/dvb/dvb-usb/Makefile 2009-01-06 00:20:40.000000000 +0100
@@ -54,6 +54,8 @@ obj-$(CONFIG_DVB_USB_DIB0700) += dvb-usb
dvb-usb-opera-objs = opera1.o
obj-$(CONFIG_DVB_USB_OPERA1) += dvb-usb-opera.o
+dvb-usb-pctv200e-objs = pctv200e.o
+obj-$(CONFIG_DVB_USB_PCTV200E) += dvb-usb-pctv200e.o
dvb-usb-af9005-objs = af9005.o af9005-fe.o
obj-$(CONFIG_DVB_USB_AF9005) += dvb-usb-af9005.o
diff -uprN v4l-dvd/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h my_v4l-dvb/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
--- v4l-dvd/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h 2009-01-06 00:16:39.000000000 +0100
+++ my_v4l-dvb/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h 2009-01-06 00:31:01.000000000 +0100
@@ -174,6 +174,7 @@
#define USB_PID_PINNACLE_PCTV73E 0x0237
#define USB_PID_PINNACLE_PCTV801E 0x023a
#define USB_PID_PINNACLE_PCTV801E_SE 0x023b
+#define USB_PID_PCTV_60E 0x0216
#define USB_PID_PCTV_200E 0x020e
#define USB_PID_PCTV_400E 0x020f
#define USB_PID_PCTV_450E 0x0222
diff -uprN v4l-dvd/linux/drivers/media/dvb/dvb-usb/pctv200e.c my_v4l-dvb/linux/drivers/media/dvb/dvb-usb/pctv200e.c
--- v4l-dvd/linux/drivers/media/dvb/dvb-usb/pctv200e.c 1970-01-01 01:00:00.000000000 +0100
+++ my_v4l-dvb/linux/drivers/media/dvb/dvb-usb/pctv200e.c 2009-01-06 15:30:32.000000000 +0100
@@ -0,0 +1,644 @@
+/*
+ * DVB USB compliant linux driver for Pinnacle PCTV 200e DVB-T reciever
+ *
+ * Copyright (C) 2008 Gabriele Dini Ciacci <g...@diniciacci.org>
+ * 2007 Jakob Steidl (jakob.ste...@gmail.com)
+ * 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 value 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 v4l_dvb_tuner_ops *ops, struct dvb_int_frontend_parameters *fep)
+{
+ warn ("pctv200e_mt2060_tuner_set_params: setting parameters!");
+
+ ops->set_params (ops,fep);
+
+ // ret = fe->ops.tuner_ops.set_params(fe, fep);
+
+ return 0;
+}
+*/
+
+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)
+{
+ warn(" trying to attach a frontend.");
+ 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 = 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 mt352frontend attached.");
+// pctv200e_cmd_msg(adap->dev, cmd_buf1, sizeof(cmd_buf1));
+ pctv200e_mt352_demod_init (adap->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(" frontend attached.");
+ return 0;
+ }
+ warn(" frontend attach FAILED.");
+ return -EIO;
+}
+
+static int pctv200e_tuner_attach(struct dvb_usb_adapter *adap)
+{
+
+ warn(" trying to attach a tuner.");
+ // 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->ops.tuner_ops,
+ if ((dvb_attach(mt2060_attach, adap->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.");
+ // if (!dvb_attach(dvb_pll_attach, adap->fe, 0xc0, NULL, DVB_PLL_TDED4)) return -ENODEV;
+ // warn("pll tuner attached.");
+ return 0;
+ }
+
+ warn("frontend_attach failed (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)
+{
+// Scheduled for removal [GDC]
+// struct dvb_usb_device *d;
+// cause we removed &d from next one.
+ int ret;
+ if ((ret = dvb_usb_device_init(intf, &pctv200e_properties,
+ THIS_MODULE, NULL, adapter_nr)) == 0) {
+#if 0
+ u8 b[4] = { 0 };
+// Do not know if we use this here, or change all the functions to take
+// an adapter_nr as parameter.
+ struct dvb_usb_device *d = i2c_get_adapdata(adapter_nr);
+ /* 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);
+
+// change me
+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 = {
+ {
+ .frontend_attach = pctv200e_frontend_attach,
+ .tuner_attach = pctv200e_tuner_attach,
+
+ /* 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 <jakob.ste...@gmail.com>, Gabriele Dini Ciacci <gabri...@diniciacci.org>");
+MODULE_DESCRIPTION("Driver for Pinnacle PCTV 200e and 60e DVB-T USB2.0");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
diff -uprN v4l-dvd/linux/drivers/media/dvb/dvb-usb/pctv200e.h my_v4l-dvb/linux/drivers/media/dvb/dvb-usb/pctv200e.h
--- v4l-dvd/linux/drivers/media/dvb/dvb-usb/pctv200e.h 1970-01-01 01:00:00.000000000 +0100
+++ my_v4l-dvb/linux/drivers/media/dvb/dvb-usb/pctv200e.h 2008-01-02 02:09:34.000000000 +0100
@@ -0,0 +1,35 @@
+#ifndef _DVB_USB_PCTV200E_H_
+#define _DVB_USB_PCTV200E_H_
+
+#define DVB_USB_LOG_PREFIX "pctv200e"
+#include "dvb-usb.h"
+
+extern int dvb_usb_pctv200e_debug;
+#define deb_rc(args...) dprintk(dvb_usb_pctv200e_debug,0x01,args)
+
+/*
+#define USB_READ_EEPROM 1
+
+#define USB_READ_COFDM 2
+#define USB_WRITE_COFDM 5
+
+#define USB_WRITE_TUNER 6
+
+#define USB_READ_REMOTE 3
+#define USB_WRITE_REMOTE 7
+#define USB_WRITE_REMOTE_TYPE 8
+
+#define USB_DEV_INIT 9
+*/
+
+
+#define USB_READ 1
+#define USB_WRITE 2
+
+#define TUNER_ADDR 0xc0
+#define DEMUX_ADDR 0x3e
+
+
+
+
+#endif