On Sun, Oct 14, 2007 at 13:33:03 +0300, Tomi Orava wrote: > > Hi, > > Attached is a latest version of "alternative" driver for the Terratec > Cinergy T2 USB device. The driver is heavily based on existing Cinergy T2 Hi, it looks like your patch is broken again. As it wasn't a separate attachment, long lines got wrapped by the sending mailer. At least I wasn't able to save it without wrapped lines. Attached is a fixed version that applied and compiled fine for me. Regards, Tino
diff -r 1236114ff6a9 linux/drivers/media/dvb/dvb-usb/Kconfig --- a/linux/drivers/media/dvb/dvb-usb/Kconfig Sun Oct 07 02:17:09 2007 -0300 +++ b/linux/drivers/media/dvb/dvb-usb/Kconfig Thu Oct 11 22:05:07 2007 +0300 @@ -239,3 +239,11 @@ config DVB_USB_AF9005_REMOTE Say Y here to support the default remote control decoding for the Afatech AF9005 based receiver. +config DVB_USB_CINERGY_T2 + tristate "Alternative driver for Terratec CinergyT2/qanu USB2 DVB-T receiver" + depends on DVB_USB + help + Support for "TerraTec CinergyT2" USB2.0 Highspeed DVB Receivers + + Say Y if you own such a device and want to use it. + diff -r 1236114ff6a9 linux/drivers/media/dvb/dvb-usb/Makefile --- a/linux/drivers/media/dvb/dvb-usb/Makefile Sun Oct 07 02:17:09 2007 -0300 +++ b/linux/drivers/media/dvb/dvb-usb/Makefile Thu Oct 11 22:05:07 2007 +0300 @@ -61,4 +61,8 @@ dvb-usb-af9005-remote-objs = af9005-remo dvb-usb-af9005-remote-objs = af9005-remote.o obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o +dvb-usb-cinergyT2-objs = cinergyT2-core.o cinergyT2-fe.o cinergyT2-remote.o +obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o + + EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ diff -r 1236114ff6a9 linux/drivers/media/dvb/dvb-usb/cinergyT2-core.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/linux/drivers/media/dvb/dvb-usb/cinergyT2-core.c Sun Oct 14 11:25:16 2007 +0300 @@ -0,0 +1,224 @@ +/* + * TerraTec Cinergy T�/qanu USB2 DVB-T adapter. + * + * Copyright (C) 2007 Tomi Orava (tomimo@xxxxxxxxxxxxxxxxxx) + * + * Based on the dvb-usb-framework code and the + * original Terratec Cinergy T2 driver by: + * + * Copyright (C) 2004 Daniel Mack <daniel@xxxxxxx> and + * Holger Waechtler <holger@xxxxxxx> + * + * Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "cinergyT2.h" + + +/* debug */ +int dvb_usb_cinergyt2_debug; +int disable_remote; + +module_param_named(debug,dvb_usb_cinergyt2_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))."); + +module_param_named(disable_remote,disable_remote, int, 0644); +MODULE_PARM_DESC(disable_remote, "Disable remote controller support (int)"); + + +/* We are missing a release hook with usb_device data */ +struct dvb_usb_device *cinergyt2_usb_device; + +static struct dvb_usb_device_properties cinergyt2_properties; + + +/* slightly modified version of dvb_usb_generic_rw -function */ + +int cinergyt2_cmd(struct dvb_usb_device *d, char *wbuf, int wlen, char *rbuf, int rlen, int delay_ms) +{ + int actlen,ret = -ENOMEM; + + if (d->props.generic_bulk_ctrl_endpoint == 0) { + err("endpoint for generic control not specified."); + return -EINVAL; + } + + if (wbuf == NULL || wlen == 0) + return -EINVAL; + + if ((ret = mutex_lock_interruptible(&d->usb_mutex))) + return ret; + + deb_xfer(">>> "); + debug_dump(wbuf,wlen,deb_xfer); + + ret = usb_bulk_msg(d->udev,usb_sndbulkpipe(d->udev, + d->props.generic_bulk_ctrl_endpoint), wbuf,wlen,&actlen, + 2000); + + if (ret) + deb_rc("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) { + if (delay_ms) + msleep(delay_ms); + + ret = usb_bulk_msg(d->udev,usb_rcvbulkpipe(d->udev, + d->props.generic_bulk_ctrl_endpoint),rbuf,rlen,&actlen, + 2000); + + if (ret) + deb_rc("recv bulk message failed: %d",ret); + else { + deb_xfer("<<< "); + debug_dump(rbuf,actlen,deb_xfer); + ret = actlen; + } + } + mutex_unlock(&d->usb_mutex); + return ret; +} + +static int cinergyt2_streaming_ctrl(struct dvb_usb_adapter *adap, int enable) +{ + char buf [] = { CINERGYT2_EP1_CONTROL_STREAM_TRANSFER, enable ? 1 : 0 }; + char result[64]; + return cinergyt2_cmd(adap->dev, buf, sizeof(buf), result, sizeof(result), 0); +} + +static int cinergyt2_power_ctrl(struct dvb_usb_device *d, int enable) +{ + char buf[] = { CINERGYT2_EP1_SLEEP_MODE, enable ? 0 : 1 }; + char state[3]; + return cinergyt2_cmd(d, buf, sizeof(buf), state, sizeof(state), 0); +} + +static int cinergyt2_frontend_attach(struct dvb_usb_adapter *adap) +{ + char query[] = { CINERGYT2_EP1_GET_FIRMWARE_VERSION }; + char state[3]; + int ret; + + adap->fe = cinergyt2_fe_attach(adap->dev); + + ret = cinergyt2_cmd(adap->dev, query, sizeof(query), state, sizeof(state), 0); + if (ret < 0) { + deb_rc("cinergyt2_power_ctrl() Failed to retrieve sleep state info\n"); + } + + /* Copy this pointer as we are gonna need it in the release phase */ + cinergyt2_usb_device=adap->dev; + + if ((ret = cinergyt2_remote_init(adap->dev))) + err("could not initialize remote control."); + + return 0; +} + +static int cinergyt2_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return dvb_usb_device_init(intf,&cinergyt2_properties,THIS_MODULE,NULL); +} + + +static struct usb_device_id cinergyt2_usb_table [] = { + { USB_DEVICE(USB_VID_TERRATEC, 0x0038) }, + { 0 } +}; + +MODULE_DEVICE_TABLE(usb, cinergyt2_usb_table); + +static struct dvb_usb_device_properties cinergyt2_properties = { + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = cinergyt2_streaming_ctrl, + .frontend_attach = cinergyt2_frontend_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 512, + } + } + }, + } + }, + + .power_ctrl = cinergyt2_power_ctrl, + + .rc_interval = 50, + .rc_key_map = 0, + .rc_key_map_size = 0, + .rc_query = 0, + + .generic_bulk_ctrl_endpoint = 1, + + .num_device_descs = 1, + .devices = { + { .name = "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver", + .cold_ids = {NULL}, + .warm_ids = { &cinergyt2_usb_table[0], NULL }, + }, + { NULL }, + } +}; + + +static struct usb_driver cinergyt2_driver = { +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15) + .owner = THIS_MODULE, +#endif + .name = "cinergyT2", + .probe = cinergyt2_usb_probe, + .disconnect = dvb_usb_device_exit, + .id_table = cinergyt2_usb_table +}; + +static int __init cinergyt2_usb_init(void) +{ + int err; + + if ((err = usb_register(&cinergyt2_driver))) { + err("usb_register() failed! (err %i)\n", err); + return err; + } + return 0; +} + +static void __exit cinergyt2_usb_exit(void) +{ + cinergyt2_remote_exit(cinergyt2_usb_device); + usb_deregister(&cinergyt2_driver); +} + +module_init (cinergyt2_usb_init); +module_exit (cinergyt2_usb_exit); + +MODULE_DESCRIPTION("Terratec Cinergy T2 DVB-T driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Tomi Orava"); diff -r 1236114ff6a9 linux/drivers/media/dvb/dvb-usb/cinergyT2-fe.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/linux/drivers/media/dvb/dvb-usb/cinergyT2-fe.c Sun Oct 14 11:19:30 2007 +0300 @@ -0,0 +1,336 @@ +/* + * TerraTec Cinergy T�/qanu USB2 DVB-T adapter. + * + * Copyright (C) 2007 Tomi Orava (tomimo@xxxxxxxxxxxxxxxxxx) + * + * Based on the dvb-usb-framework code and the + * original Terratec Cinergy T2 driver by: + * + * Copyright (C) 2004 Daniel Mack <daniel@xxxxxxx> and + * Holger Waechtler <holger@xxxxxxx> + * + * Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "cinergyT2.h" + + +/** + * convert linux-dvb frontend parameter set into TPS. + * See ETSI ETS-300744, section 4.6.2, table 9 for details. + * + * This function is probably reusable and may better get placed in a support + * library. + * + * We replace errornous fields by default TPS fields (the ones with value 0). + */ +static uint16_t compute_tps (struct dvb_frontend_parameters *p) +{ + struct dvb_ofdm_parameters *op = &p->u.ofdm; + uint16_t tps = 0; + + switch (op->code_rate_HP) { + case FEC_2_3: + tps |= (1 << 7); + break; + case FEC_3_4: + tps |= (2 << 7); + break; + case FEC_5_6: + tps |= (3 << 7); + break; + case FEC_7_8: + tps |= (4 << 7); + break; + case FEC_1_2: + case FEC_AUTO: + default: + /* tps |= (0 << 7) */; + } + + switch (op->code_rate_LP) { + case FEC_2_3: + tps |= (1 << 4); + break; + case FEC_3_4: + tps |= (2 << 4); + break; + case FEC_5_6: + tps |= (3 << 4); + break; + case FEC_7_8: + tps |= (4 << 4); + break; + case FEC_1_2: + case FEC_AUTO: + default: + /* tps |= (0 << 4) */; + } + + switch (op->constellation) { + case QAM_16: + tps |= (1 << 13); + break; + case QAM_64: + tps |= (2 << 13); + break; + case QPSK: + default: + /* tps |= (0 << 13) */; + } + + switch (op->transmission_mode) { + case TRANSMISSION_MODE_8K: + tps |= (1 << 0); + break; + case TRANSMISSION_MODE_2K: + default: + /* tps |= (0 << 0) */; + } + + switch (op->guard_interval) { + case GUARD_INTERVAL_1_16: + tps |= (1 << 2); + break; + case GUARD_INTERVAL_1_8: + tps |= (2 << 2); + break; + case GUARD_INTERVAL_1_4: + tps |= (3 << 2); + break; + case GUARD_INTERVAL_1_32: + default: + /* tps |= (0 << 2) */; + } + + switch (op->hierarchy_information) { + case HIERARCHY_1: + tps |= (1 << 10); + break; + case HIERARCHY_2: + tps |= (2 << 10); + break; + case HIERARCHY_4: + tps |= (3 << 10); + break; + case HIERARCHY_NONE: + default: + /* tps |= (0 << 10) */; + } + + return tps; +} + +struct cinergyt2_fe_state { + struct dvb_frontend fe; + struct dvb_usb_device *d; +}; + +static int cinergyt2_fe_read_status(struct dvb_frontend* fe, fe_status_t *status) +{ + struct cinergyt2_fe_state *state = fe->demodulator_priv; + struct dvbt_get_status_msg result; + u8 cmd [] = { CINERGYT2_EP1_GET_TUNER_STATUS }; + int ret; + + ret = cinergyt2_cmd(state->d, cmd, sizeof(cmd), (u8 *)&result, + sizeof(result), 0); + if (ret < 0) { + return ret; + } + *status = 0; + + if (0xffff - le16_to_cpu(result.gain) > 30) + *status |= FE_HAS_SIGNAL; + if (result.lock_bits & (1 << 6)) + *status |= FE_HAS_LOCK; + if (result.lock_bits & (1 << 5)) + *status |= FE_HAS_SYNC; + if (result.lock_bits & (1 << 4)) + *status |= FE_HAS_CARRIER; + if (result.lock_bits & (1 << 1)) + *status |= FE_HAS_VITERBI; + + if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) != + (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) + *status &= ~FE_HAS_LOCK; + + return 0; +} + +static int cinergyt2_fe_read_ber(struct dvb_frontend* fe, u32 *ber) +{ + struct cinergyt2_fe_state *state = fe->demodulator_priv; + struct dvbt_get_status_msg status; + char cmd [] = { CINERGYT2_EP1_GET_TUNER_STATUS }; + int ret; + + ret = cinergyt2_cmd(state->d, cmd, sizeof(cmd), (char *)&status, sizeof(status), 0); + if (ret < 0) { + return ret; + } + *ber = le32_to_cpu(status.viterbi_error_rate); + return 0; +} + +static int cinergyt2_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) +{ + struct cinergyt2_fe_state *state = fe->demodulator_priv; + struct dvbt_get_status_msg status; + u8 cmd [] = { CINERGYT2_EP1_GET_TUNER_STATUS }; + int ret; + + ret = cinergyt2_cmd(state->d, cmd, sizeof(cmd), (u8 *)&status, sizeof(status), 0); + if (ret < 0) { + err("cinergyt2_fe_read_unc_blocks() Failed! (Error=%d)\n", ret); + return ret; + } + *unc = le32_to_cpu(status.uncorrected_block_count); + return 0; +} + +static int cinergyt2_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength) +{ + struct cinergyt2_fe_state *state = fe->demodulator_priv; + struct dvbt_get_status_msg status; + char cmd [] = { CINERGYT2_EP1_GET_TUNER_STATUS }; + int ret; + + ret = cinergyt2_cmd(state->d, cmd, sizeof(cmd), (char *)&status, sizeof(status), 0); + if (ret < 0) { + err("cinergyt2_fe_read_signal_strength() Failed! (Error=%d)\n", ret); + return ret; + } + *strength = (0xffff - le16_to_cpu(status.gain)); + return 0; +} + +static int cinergyt2_fe_read_snr(struct dvb_frontend* fe, u16 *snr) +{ + struct cinergyt2_fe_state *state = fe->demodulator_priv; + struct dvbt_get_status_msg status; + char cmd [] = { CINERGYT2_EP1_GET_TUNER_STATUS }; + int ret; + + ret = cinergyt2_cmd(state->d, cmd, sizeof(cmd), (char *)&status, sizeof(status), 0); + if (ret < 0) { + err("cinergyt2_fe_read_snr() Failed! (Error=%d)\n", ret); + return ret; + } + *snr = (status.snr << 8) | status.snr; + return 0; +} + +static int cinergyt2_fe_init(struct dvb_frontend* fe) +{ + return 0; +} + +static int cinergyt2_fe_sleep(struct dvb_frontend* fe) +{ + deb_info("cinergyt2_fe_sleep() Called\n"); + return 0; +} + +static int cinergyt2_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 800; + return 0; +} + +static int cinergyt2_fe_set_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *fep) +{ + struct cinergyt2_fe_state *state = fe->demodulator_priv; + struct dvbt_set_parameters_msg param; + char result[2]; + int err; + + param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS; + param.tps = cpu_to_le16(compute_tps(fep)); + param.freq = cpu_to_le32(fep->frequency / 1000); + param.bandwidth = 8 - fep->u.ofdm.bandwidth - BANDWIDTH_8_MHZ; + + err = cinergyt2_cmd(state->d, + (char *)¶m, sizeof(param), + result, sizeof(result), 0); + if (err < 0) { + err("cinergyt2_fe_set_frontend() Failed! err=%d\n", err); + } + + return (err < 0) ? err : 0; +} + +static int cinergyt2_fe_get_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *fep) +{ + return 0; +} + +static void cinergyt2_fe_release(struct dvb_frontend* fe) +{ + struct cinergyt2_fe_state *state = fe->demodulator_priv; + if (state != NULL) + kfree(state); +} + +static struct dvb_frontend_ops cinergyt2_fe_ops; + +struct dvb_frontend * cinergyt2_fe_attach(struct dvb_usb_device *d) +{ + struct cinergyt2_fe_state *s = kzalloc(sizeof(struct cinergyt2_fe_state), GFP_KERNEL); + if (s == NULL) + return NULL; + + s->d = d; + memcpy(&s->fe.ops, &cinergyt2_fe_ops, sizeof(struct dvb_frontend_ops)); + s->fe.demodulator_priv = s; + return &s->fe; +} + + +static struct dvb_frontend_ops cinergyt2_fe_ops = { + .info = { + .name = DRIVER_NAME, + .type = FE_OFDM, + .frequency_min = 174000000, + .frequency_max = 862000000, + .frequency_stepsize = 166667, + .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_HIERARCHY_AUTO | FE_CAN_RECOVER | FE_CAN_MUTE_TS + }, + + .release = cinergyt2_fe_release, + + .init = cinergyt2_fe_init, + .sleep = cinergyt2_fe_sleep, + + .set_frontend = cinergyt2_fe_set_frontend, + .get_frontend = cinergyt2_fe_get_frontend, + .get_tune_settings = cinergyt2_fe_get_tune_settings, + + .read_status = cinergyt2_fe_read_status, + .read_ber = cinergyt2_fe_read_ber, + .read_signal_strength = cinergyt2_fe_read_signal_strength, + .read_snr = cinergyt2_fe_read_snr, + .read_ucblocks = cinergyt2_fe_read_unc_blocks, +}; diff -r 1236114ff6a9 linux/drivers/media/dvb/dvb-usb/cinergyT2-remote.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/linux/drivers/media/dvb/dvb-usb/cinergyT2-remote.c Sun Oct 14 11:28:58 2007 +0300 @@ -0,0 +1,309 @@ +/* + * TerraTec Cinergy T�/qanu USB2 DVB-T adapter. + * + * Copyright (C) 2007 Tomi Orava (tomimo@xxxxxxxxxxxxxxxxxx) + * + * Based on the dvb-usb-framework code and the + * original Terratec Cinergy T2 driver by: + * + * Copyright (C) 2004 Daniel Mack <daniel@xxxxxxx> and + * Holger Waechtler <holger@xxxxxxx> + * + * Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "cinergyT2.h" + +enum { + CINERGYT2_RC_EVENT_TYPE_NONE = 0x00, + CINERGYT2_RC_EVENT_TYPE_NEC = 0x01, + CINERGYT2_RC_EVENT_TYPE_RC5 = 0x02 +}; + +/** + * struct dvb_usb_rc_key - a remote control key and its input-event + * @custom: the vendor/custom part of the key + * @data: the actual key part + * @event: the input event assigned to key identified by custom and data + */ +struct cinergyt2_rc_key { + u32 custom; + u32 data; + u32 event; +}; + + +struct cinergyt2_rc_event { + char custom; + uint32_t data; +} __attribute__((packed)); + + + +extern int disable_remote; + +struct cinergyt2_rc_key cinergyt2_rc_keys[] = { + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xfe01eb04, KEY_POWER }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xfd02eb04, KEY_1 }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xfc03eb04, KEY_2 }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xfb04eb04, KEY_3 }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xfa05eb04, KEY_4 }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xf906eb04, KEY_5 }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xf807eb04, KEY_6 }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xf708eb04, KEY_7 }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xf609eb04, KEY_8 }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xf50aeb04, KEY_9 }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xf30ceb04, KEY_0 }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xf40beb04, KEY_VIDEO }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xf20deb04, KEY_REFRESH }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xf10eeb04, KEY_SELECT }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xf00feb04, KEY_EPG }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xef10eb04, KEY_UP }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xeb14eb04, KEY_DOWN }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xee11eb04, KEY_LEFT }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xec13eb04, KEY_RIGHT }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xed12eb04, KEY_ENTER }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xea15eb04, KEY_TEXT }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xe916eb04, KEY_INFO }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xe817eb04, KEY_RED }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xe718eb04, KEY_GREEN }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xe619eb04, KEY_YELLOW }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xe51aeb04, KEY_ESC }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xe31ceb04, KEY_VOLUMEUP }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xe11eeb04, KEY_VOLUMEDOWN }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xe21deb04, KEY_MUTE }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xe41beb04, KEY_CHANNELUP }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xe01feb04, KEY_CHANNELDOWN }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xbf40eb04, KEY_PAUSE }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xb34ceb04, KEY_PLAY }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xa758eb04, KEY_RECORD }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xab54eb04, KEY_PREVIOUS }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xb748eb04, KEY_STOP }, + { CINERGYT2_RC_EVENT_TYPE_NEC, 0xa35ceb04, KEY_NEXT } +}; + +int cinergyt2_rc_keys_size = ARRAY_SIZE(cinergyt2_rc_keys); + + +static int cinergyt2_decode_rc_key(struct dvb_usb_device *dev, int type, int data, u32 *event, int *state) { + int i, key, found; + + *state = REMOTE_NO_KEY_PRESSED; + key=le32_to_cpu(data); + + /* info("cinergyt2_decode_rc_key() type=%d, key=0x%x (converted=0x%x)\n", type, data, key); */ + + switch (type) { + case CINERGYT2_RC_EVENT_TYPE_NEC: + if (key == ~0) { + /* Stop key repeat */ + *state = REMOTE_NO_KEY_PRESSED; + break; + } + + found=0; + for (i = 0; i < cinergyt2_rc_keys_size; i++) { + if (cinergyt2_rc_keys[i].data == key) { + *event = cinergyt2_rc_keys[i].event; + *state = REMOTE_KEY_PRESSED; + found=1; + /* deb_info("Remote key pressed! key=%d\n", i); */ + break; + } + } + if (found == 0) + err("cinergyT2: Unknown remote control key detected! key=0x%x (raw=0x%x)\n", key, data); + break; + + case CINERGYT2_RC_EVENT_TYPE_RC5: + case CINERGYT2_RC_EVENT_TYPE_NONE: + default: + info("Unhandled remote key detected! type=0x%x\n", type); + break; + } + return 0; +} + +static int cinergyt2_rc_process(struct dvb_usb_device *dev) +{ + char buf[1] = { CINERGYT2_EP1_GET_RC_EVENTS }; + struct cinergyt2_rc_event rc_events[12]; + int len, i, state; + u32 event; + /* struct cinergyt2_device_state *st = dev->priv; */ + + len = cinergyt2_cmd(dev, buf, sizeof(buf), + (char *)rc_events, sizeof(rc_events), 0); + if (len < 0) { + /* printk(KERN_INFO "Failed to read RC event data!\n"); */ + return 0; + } + + if (len==0) + return 0; + + state = REMOTE_NO_KEY_PRESSED; + + for (i = 0; i < (len / sizeof(rc_events[0])); i++) { + /* deb_info("[%d/%d] rc_events[%d].data = %x (converted=%x), type=%x\n", + * i, len / sizeof(rc_events[0]), i, rc_events[i].data, le32_to_cpu(rc_events[i].data), rc_events[i].custom); + */ + + cinergyt2_decode_rc_key(dev, rc_events[i].custom, rc_events[i].data, &event, &state); + switch (state) { + case REMOTE_NO_KEY_PRESSED: + break; + + case REMOTE_KEY_PRESSED: + /* deb_rc("key pressed\n"); */ + dev->last_event = event; + input_event(dev->rc_input_dev, EV_KEY, event, 1); + input_event(dev->rc_input_dev, EV_KEY, dev->last_event, 0); + input_sync(dev->rc_input_dev); + break; + + case REMOTE_KEY_REPEAT: + /* deb_rc("key repeated\n"); */ + input_event(dev->rc_input_dev, EV_KEY, event, 1); + input_event(dev->rc_input_dev, EV_KEY, dev->last_event, 0); + input_sync(dev->rc_input_dev); + break; + default: + break; + } + + } + return 0; +} + +/* + * Code copied from dvb-usb-remote.c and modified for Cinergy T2 + */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +static void cinergyt2_read_remote_control(void *data) +#else +static void cinergyt2_read_remote_control(struct work_struct *work) +#endif +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + struct dvb_usb_device *d = data; +#else + struct dvb_usb_device *d = + container_of(work, struct dvb_usb_device, rc_query_work.work); +#endif + + /* TODO: need a lock here. We can simply skip checking for the remote control + if we're busy. */ + + /* when the parameter has been set to 1 via sysfs while the driver was running */ + if (disable_remote) + return; + + if (cinergyt2_rc_process(d)) + err("error while querying for an remote control event."); + + schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc_interval)); +} + + + +int cinergyt2_remote_init(struct dvb_usb_device *d) +{ + struct input_dev *input_dev; + int i; + int err; + + if (disable_remote) { + err("Remote controller support disabled!\n"); + return 0; + } + + usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); + strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys)); + + input_dev = input_allocate_device(); + if (!input_dev) { + err("Failed to allocate new input device!\n"); + return -ENOMEM; + } + + input_dev->evbit[0] = BIT(EV_KEY); + input_dev->name = "IR-receiver inside an USB DVB receiver"; + input_dev->phys = d->rc_phys; + usb_to_input_id(d->udev, &input_dev->id); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) + input_dev->dev.parent = &d->udev->dev; +#else +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) + input_dev->cdev.dev = &d->udev->dev; +#endif +#endif + + /* set the bits for the keys */ + deb_rc("key map size: %d\n", cinergyt2_rc_keys_size); + for (i = 0; i < cinergyt2_rc_keys_size; i++) { + deb_rc("setting bit for event %d item %d\n", + cinergyt2_rc_keys[i].event, i); + set_bit(cinergyt2_rc_keys[i].event, input_dev->keybit); + } + + /* Start the remote-control polling. */ + if (d->props.rc_interval < 40) + d->props.rc_interval = 100; /* default */ + + /* setting these two values to non-zero, we have to manage key repeats */ + input_dev->rep[REP_PERIOD] = d->props.rc_interval; + input_dev->rep[REP_DELAY] = d->props.rc_interval + 150; + + err = input_register_device(input_dev); + if (err) { + input_free_device(input_dev); + err("Failed to register new input device!\n"); + return err; + } + + d->rc_input_dev = input_dev; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + INIT_WORK(&d->rc_query_work, cinergyt2_read_remote_control, d); +#else + INIT_DELAYED_WORK(&d->rc_query_work, cinergyt2_read_remote_control); +#endif + + info("schedule remote query interval to %d msecs.", d->props.rc_interval); + schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc_interval)); + + d->state |= DVB_USB_STATE_REMOTE; + + return 0; +} + +int cinergyt2_remote_exit(struct dvb_usb_device *d) +{ + if (d->state & DVB_USB_STATE_REMOTE) { + cancel_rearming_delayed_work(&d->rc_query_work); + flush_scheduled_work(); + input_unregister_device(d->rc_input_dev); + } + d->state &= ~DVB_USB_STATE_REMOTE; + return 0; +} + +EXPORT_SYMBOL(cinergyt2_remote_init); +EXPORT_SYMBOL(cinergyt2_remote_exit); diff -r 1236114ff6a9 linux/drivers/media/dvb/dvb-usb/cinergyT2.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/linux/drivers/media/dvb/dvb-usb/cinergyT2.h Sun Oct 14 11:02:59 2007 +0300 @@ -0,0 +1,106 @@ +/* + * TerraTec Cinergy T�/qanu USB2 DVB-T adapter. + * + * Copyright (C) 2007 Tomi Orava (tomimo@xxxxxxxxxxxxxxxxxx) + * + * Based on the dvb-usb-framework code and the + * original Terratec Cinergy T2 driver by: + * + * Copyright (C) 2004 Daniel Mack <daniel@xxxxxxx> and + * Holger Waechtler <holger@xxxxxxx> + * + * Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _DVB_USB_CINERGYT2_H_ +#define _DVB_USB_CINERGYT2_H_ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) +#include <linux/usb/input.h> +#else +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) +#include <linux/usb_input.h> +#endif +#endif + + +#define DVB_USB_LOG_PREFIX "cinergyT2" +#include "dvb-usb.h" + +#define DRIVER_NAME "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver" + +extern int disable_remote; +extern int dvb_usb_cinergyt2_debug; + +#define deb_info(args...) dprintk(dvb_usb_cinergyt2_debug,0x001,args) +#define deb_xfer(args...) dprintk(dvb_usb_cinergyt2_debug,0x002,args) +#define deb_pll(args...) dprintk(dvb_usb_cinergyt2_debug,0x004,args) +#define deb_ts(args...) dprintk(dvb_usb_cinergyt2_debug,0x008,args) +#define deb_err(args...) dprintk(dvb_usb_cinergyt2_debug,0x010,args) +#define deb_rc(args...) dprintk(dvb_usb_cinergyt2_debug,0x020,args) +#define deb_fw(args...) dprintk(dvb_usb_cinergyt2_debug,0x040,args) +#define deb_mem(args...) dprintk(dvb_usb_cinergyt2_debug,0x080,args) +#define deb_uxfer(args...) dprintk(dvb_usb_cinergyt2_debug,0x100,args) + + + +enum cinergyt2_ep1_cmd { + CINERGYT2_EP1_PID_TABLE_RESET = 0x01, + CINERGYT2_EP1_PID_SETUP = 0x02, + CINERGYT2_EP1_CONTROL_STREAM_TRANSFER = 0x03, + CINERGYT2_EP1_SET_TUNER_PARAMETERS = 0x04, + CINERGYT2_EP1_GET_TUNER_STATUS = 0x05, + CINERGYT2_EP1_START_SCAN = 0x06, + CINERGYT2_EP1_CONTINUE_SCAN = 0x07, + CINERGYT2_EP1_GET_RC_EVENTS = 0x08, + CINERGYT2_EP1_SLEEP_MODE = 0x09, + CINERGYT2_EP1_GET_FIRMWARE_VERSION = 0x0A +}; + + +struct dvbt_get_status_msg { + uint32_t freq; + uint8_t bandwidth; + uint16_t tps; + uint8_t flags; + uint16_t gain; + uint8_t snr; + uint32_t viterbi_error_rate; + uint32_t rs_error_rate; + uint32_t uncorrected_block_count; + uint8_t lock_bits; + uint8_t prev_lock_bits; +} __attribute__((packed)); + + +struct dvbt_set_parameters_msg { + uint8_t cmd; + uint32_t freq; + uint8_t bandwidth; + uint16_t tps; + uint8_t flags; +} __attribute__((packed)); + + +extern struct dvb_frontend * cinergyt2_fe_attach(struct dvb_usb_device *d); +extern int cinergyt2_cmd(struct dvb_usb_device *d, char *wbuf, int wlen, char *rbuf, int rlen, int delay_ms); + +extern int cinergyt2_remote_init(struct dvb_usb_device *d); +extern int cinergyt2_remote_exit(struct dvb_usb_device *d); + +#endif /* _DVB_USB_CINERGYT2_H_ */
_______________________________________________ linux-dvb mailing list linux-dvb@xxxxxxxxxxx http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb