Updated unofficial driver for Pinnacle PCTV200e

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 (jakob.steidl@xxxxxxxxx)
 *               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 <jakob.steidl@xxxxxxxxx>");
MODULE_DESCRIPTION("Driver for Pinnacle PCTV 200e DVB-T USB2.0");
MODULE_VERSION("0.1");
MODULE_LICENSE("GPL");

[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux