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");