18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/* DVB USB compliant linux driver for Technotrend DVB USB boxes and clones
38c2ecf20Sopenharmony_ci * (e.g. Pinnacle 400e DVB-S USB2.0).
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * The Pinnacle 400e uses the same protocol as the Technotrend USB1.1 boxes.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * TDA8263 + TDA10086
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * I2C addresses:
108c2ecf20Sopenharmony_ci * 0x08 - LNBP21PD   - LNB power supply
118c2ecf20Sopenharmony_ci * 0x0e - TDA10086   - Demodulator
128c2ecf20Sopenharmony_ci * 0x50 - FX2 eeprom
138c2ecf20Sopenharmony_ci * 0x60 - TDA8263    - Tuner
148c2ecf20Sopenharmony_ci * 0x78 ???
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * Copyright (c) 2002 Holger Waechtler <holger@convergence.de>
178c2ecf20Sopenharmony_ci * Copyright (c) 2003 Felix Domke <tmbinc@elitedvb.net>
188c2ecf20Sopenharmony_ci * Copyright (C) 2005-6 Patrick Boettcher <pb@linuxtv.org>
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci * see Documentation/driver-api/media/drivers/dvb-usb.rst for more information
218c2ecf20Sopenharmony_ci */
228c2ecf20Sopenharmony_ci#define DVB_USB_LOG_PREFIX "ttusb2"
238c2ecf20Sopenharmony_ci#include "dvb-usb.h"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include "ttusb2.h"
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#include "tda826x.h"
288c2ecf20Sopenharmony_ci#include "tda10086.h"
298c2ecf20Sopenharmony_ci#include "tda1002x.h"
308c2ecf20Sopenharmony_ci#include "tda10048.h"
318c2ecf20Sopenharmony_ci#include "tda827x.h"
328c2ecf20Sopenharmony_ci#include "lnbp21.h"
338c2ecf20Sopenharmony_ci/* CA */
348c2ecf20Sopenharmony_ci#include <media/dvb_ca_en50221.h>
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci/* debug */
378c2ecf20Sopenharmony_cistatic int dvb_usb_ttusb2_debug;
388c2ecf20Sopenharmony_ci#define deb_info(args...)   dprintk(dvb_usb_ttusb2_debug,0x01,args)
398c2ecf20Sopenharmony_cimodule_param_named(debug,dvb_usb_ttusb2_debug, int, 0644);
408c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))." DVB_USB_DEBUG_STATUS);
418c2ecf20Sopenharmony_cistatic int dvb_usb_ttusb2_debug_ci;
428c2ecf20Sopenharmony_cimodule_param_named(debug_ci,dvb_usb_ttusb2_debug_ci, int, 0644);
438c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug_ci, "set debugging ci." DVB_USB_DEBUG_STATUS);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ciDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci#define ci_dbg(format, arg...)                \
488c2ecf20Sopenharmony_cido {                                          \
498c2ecf20Sopenharmony_ci	if (dvb_usb_ttusb2_debug_ci)                                    \
508c2ecf20Sopenharmony_ci		printk(KERN_DEBUG DVB_USB_LOG_PREFIX \
518c2ecf20Sopenharmony_ci			": %s " format "\n" , __func__, ## arg);       \
528c2ecf20Sopenharmony_ci} while (0)
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cienum {
558c2ecf20Sopenharmony_ci	TT3650_CMD_CI_TEST = 0x40,
568c2ecf20Sopenharmony_ci	TT3650_CMD_CI_RD_CTRL,
578c2ecf20Sopenharmony_ci	TT3650_CMD_CI_WR_CTRL,
588c2ecf20Sopenharmony_ci	TT3650_CMD_CI_RD_ATTR,
598c2ecf20Sopenharmony_ci	TT3650_CMD_CI_WR_ATTR,
608c2ecf20Sopenharmony_ci	TT3650_CMD_CI_RESET,
618c2ecf20Sopenharmony_ci	TT3650_CMD_CI_SET_VIDEO_PORT
628c2ecf20Sopenharmony_ci};
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistruct ttusb2_state {
658c2ecf20Sopenharmony_ci	struct dvb_ca_en50221 ca;
668c2ecf20Sopenharmony_ci	struct mutex ca_mutex;
678c2ecf20Sopenharmony_ci	u8 id;
688c2ecf20Sopenharmony_ci	u16 last_rc_key;
698c2ecf20Sopenharmony_ci};
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic int ttusb2_msg(struct dvb_usb_device *d, u8 cmd,
728c2ecf20Sopenharmony_ci		u8 *wbuf, int wlen, u8 *rbuf, int rlen)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	struct ttusb2_state *st = d->priv;
758c2ecf20Sopenharmony_ci	u8 *s, *r = NULL;
768c2ecf20Sopenharmony_ci	int ret = 0;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	if (4 + rlen > 64)
798c2ecf20Sopenharmony_ci		return -EIO;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	s = kzalloc(wlen+4, GFP_KERNEL);
828c2ecf20Sopenharmony_ci	if (!s)
838c2ecf20Sopenharmony_ci		return -ENOMEM;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	r = kzalloc(64, GFP_KERNEL);
868c2ecf20Sopenharmony_ci	if (!r) {
878c2ecf20Sopenharmony_ci		kfree(s);
888c2ecf20Sopenharmony_ci		return -ENOMEM;
898c2ecf20Sopenharmony_ci	}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	s[0] = 0xaa;
928c2ecf20Sopenharmony_ci	s[1] = ++st->id;
938c2ecf20Sopenharmony_ci	s[2] = cmd;
948c2ecf20Sopenharmony_ci	s[3] = wlen;
958c2ecf20Sopenharmony_ci	memcpy(&s[4],wbuf,wlen);
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	ret = dvb_usb_generic_rw(d, s, wlen+4, r, 64, 0);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	if (ret  != 0 ||
1008c2ecf20Sopenharmony_ci		r[0] != 0x55 ||
1018c2ecf20Sopenharmony_ci		r[1] != s[1] ||
1028c2ecf20Sopenharmony_ci		r[2] != cmd ||
1038c2ecf20Sopenharmony_ci		(rlen > 0 && r[3] != rlen)) {
1048c2ecf20Sopenharmony_ci		warn("there might have been an error during control message transfer. (rlen = %d, was %d)",rlen,r[3]);
1058c2ecf20Sopenharmony_ci		kfree(s);
1068c2ecf20Sopenharmony_ci		kfree(r);
1078c2ecf20Sopenharmony_ci		return -EIO;
1088c2ecf20Sopenharmony_ci	}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	if (rlen > 0)
1118c2ecf20Sopenharmony_ci		memcpy(rbuf, &r[4], rlen);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	kfree(s);
1148c2ecf20Sopenharmony_ci	kfree(r);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	return 0;
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci/* ci */
1208c2ecf20Sopenharmony_cistatic int tt3650_ci_msg(struct dvb_usb_device *d, u8 cmd, u8 *data, unsigned int write_len, unsigned int read_len)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	int ret;
1238c2ecf20Sopenharmony_ci	u8 rx[60];/* (64 -4) */
1248c2ecf20Sopenharmony_ci	ret = ttusb2_msg(d, cmd, data, write_len, rx, read_len);
1258c2ecf20Sopenharmony_ci	if (!ret)
1268c2ecf20Sopenharmony_ci		memcpy(data, rx, read_len);
1278c2ecf20Sopenharmony_ci	return ret;
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic int tt3650_ci_msg_locked(struct dvb_ca_en50221 *ca, u8 cmd, u8 *data, unsigned int write_len, unsigned int read_len)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	struct dvb_usb_device *d = ca->data;
1338c2ecf20Sopenharmony_ci	struct ttusb2_state *state = d->priv;
1348c2ecf20Sopenharmony_ci	int ret;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	mutex_lock(&state->ca_mutex);
1378c2ecf20Sopenharmony_ci	ret = tt3650_ci_msg(d, cmd, data, write_len, read_len);
1388c2ecf20Sopenharmony_ci	mutex_unlock(&state->ca_mutex);
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	return ret;
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic int tt3650_ci_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	u8 buf[3];
1468c2ecf20Sopenharmony_ci	int ret = 0;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	if (slot)
1498c2ecf20Sopenharmony_ci		return -EINVAL;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	buf[0] = (address >> 8) & 0x0F;
1528c2ecf20Sopenharmony_ci	buf[1] = address;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_ATTR, buf, 2, 3);
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	ci_dbg("%04x -> %d 0x%02x", address, ret, buf[2]);
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	if (ret < 0)
1608c2ecf20Sopenharmony_ci		return ret;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	return buf[2];
1638c2ecf20Sopenharmony_ci}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_cistatic int tt3650_ci_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
1668c2ecf20Sopenharmony_ci{
1678c2ecf20Sopenharmony_ci	u8 buf[3];
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	ci_dbg("%d 0x%04x 0x%02x", slot, address, value);
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	if (slot)
1728c2ecf20Sopenharmony_ci		return -EINVAL;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	buf[0] = (address >> 8) & 0x0F;
1758c2ecf20Sopenharmony_ci	buf[1] = address;
1768c2ecf20Sopenharmony_ci	buf[2] = value;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_ATTR, buf, 3, 3);
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistatic int tt3650_ci_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	u8 buf[2];
1848c2ecf20Sopenharmony_ci	int ret;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	if (slot)
1878c2ecf20Sopenharmony_ci		return -EINVAL;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	buf[0] = address & 3;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_CTRL, buf, 1, 2);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	ci_dbg("0x%02x -> %d 0x%02x", address, ret, buf[1]);
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	if (ret < 0)
1968c2ecf20Sopenharmony_ci		return ret;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	return buf[1];
1998c2ecf20Sopenharmony_ci}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_cistatic int tt3650_ci_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
2028c2ecf20Sopenharmony_ci{
2038c2ecf20Sopenharmony_ci	u8 buf[2];
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	ci_dbg("%d 0x%02x 0x%02x", slot, address, value);
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	if (slot)
2088c2ecf20Sopenharmony_ci		return -EINVAL;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	buf[0] = address;
2118c2ecf20Sopenharmony_ci	buf[1] = value;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_CTRL, buf, 2, 2);
2148c2ecf20Sopenharmony_ci}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_cistatic int tt3650_ci_set_video_port(struct dvb_ca_en50221 *ca, int slot, int enable)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	u8 buf[1];
2198c2ecf20Sopenharmony_ci	int ret;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	ci_dbg("%d %d", slot, enable);
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	if (slot)
2248c2ecf20Sopenharmony_ci		return -EINVAL;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	buf[0] = enable;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
2298c2ecf20Sopenharmony_ci	if (ret < 0)
2308c2ecf20Sopenharmony_ci		return ret;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	if (enable != buf[0]) {
2338c2ecf20Sopenharmony_ci		err("CI not %sabled.", enable ? "en" : "dis");
2348c2ecf20Sopenharmony_ci		return -EIO;
2358c2ecf20Sopenharmony_ci	}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	return 0;
2388c2ecf20Sopenharmony_ci}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_cistatic int tt3650_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
2418c2ecf20Sopenharmony_ci{
2428c2ecf20Sopenharmony_ci	return tt3650_ci_set_video_port(ca, slot, 0);
2438c2ecf20Sopenharmony_ci}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_cistatic int tt3650_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
2468c2ecf20Sopenharmony_ci{
2478c2ecf20Sopenharmony_ci	return tt3650_ci_set_video_port(ca, slot, 1);
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_cistatic int tt3650_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
2518c2ecf20Sopenharmony_ci{
2528c2ecf20Sopenharmony_ci	struct dvb_usb_device *d = ca->data;
2538c2ecf20Sopenharmony_ci	struct ttusb2_state *state = d->priv;
2548c2ecf20Sopenharmony_ci	u8 buf[1];
2558c2ecf20Sopenharmony_ci	int ret;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	ci_dbg("%d", slot);
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	if (slot)
2608c2ecf20Sopenharmony_ci		return -EINVAL;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	buf[0] = 0;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	mutex_lock(&state->ca_mutex);
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
2678c2ecf20Sopenharmony_ci	if (ret)
2688c2ecf20Sopenharmony_ci		goto failed;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	msleep(500);
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	buf[0] = 1;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
2758c2ecf20Sopenharmony_ci	if (ret)
2768c2ecf20Sopenharmony_ci		goto failed;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	msleep(500);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	buf[0] = 0; /* FTA */
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	ret = tt3650_ci_msg(d, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	msleep(1100);
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci failed:
2878c2ecf20Sopenharmony_ci	mutex_unlock(&state->ca_mutex);
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	return ret;
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_cistatic int tt3650_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	u8 buf[1];
2958c2ecf20Sopenharmony_ci	int ret;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	if (slot)
2988c2ecf20Sopenharmony_ci		return -EINVAL;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_TEST, buf, 0, 1);
3018c2ecf20Sopenharmony_ci	if (ret)
3028c2ecf20Sopenharmony_ci		return ret;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	if (1 == buf[0]) {
3058c2ecf20Sopenharmony_ci		return DVB_CA_EN50221_POLL_CAM_PRESENT |
3068c2ecf20Sopenharmony_ci			DVB_CA_EN50221_POLL_CAM_READY;
3078c2ecf20Sopenharmony_ci	}
3088c2ecf20Sopenharmony_ci	return 0;
3098c2ecf20Sopenharmony_ci}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_cistatic void tt3650_ci_uninit(struct dvb_usb_device *d)
3128c2ecf20Sopenharmony_ci{
3138c2ecf20Sopenharmony_ci	struct ttusb2_state *state;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	ci_dbg("");
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	if (NULL == d)
3188c2ecf20Sopenharmony_ci		return;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	state = d->priv;
3218c2ecf20Sopenharmony_ci	if (NULL == state)
3228c2ecf20Sopenharmony_ci		return;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	if (NULL == state->ca.data)
3258c2ecf20Sopenharmony_ci		return;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	dvb_ca_en50221_release(&state->ca);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	memset(&state->ca, 0, sizeof(state->ca));
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_cistatic int tt3650_ci_init(struct dvb_usb_adapter *a)
3338c2ecf20Sopenharmony_ci{
3348c2ecf20Sopenharmony_ci	struct dvb_usb_device *d = a->dev;
3358c2ecf20Sopenharmony_ci	struct ttusb2_state *state = d->priv;
3368c2ecf20Sopenharmony_ci	int ret;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	ci_dbg("");
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	mutex_init(&state->ca_mutex);
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	state->ca.owner = THIS_MODULE;
3438c2ecf20Sopenharmony_ci	state->ca.read_attribute_mem = tt3650_ci_read_attribute_mem;
3448c2ecf20Sopenharmony_ci	state->ca.write_attribute_mem = tt3650_ci_write_attribute_mem;
3458c2ecf20Sopenharmony_ci	state->ca.read_cam_control = tt3650_ci_read_cam_control;
3468c2ecf20Sopenharmony_ci	state->ca.write_cam_control = tt3650_ci_write_cam_control;
3478c2ecf20Sopenharmony_ci	state->ca.slot_reset = tt3650_ci_slot_reset;
3488c2ecf20Sopenharmony_ci	state->ca.slot_shutdown = tt3650_ci_slot_shutdown;
3498c2ecf20Sopenharmony_ci	state->ca.slot_ts_enable = tt3650_ci_slot_ts_enable;
3508c2ecf20Sopenharmony_ci	state->ca.poll_slot_status = tt3650_ci_poll_slot_status;
3518c2ecf20Sopenharmony_ci	state->ca.data = d;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	ret = dvb_ca_en50221_init(&a->dvb_adap,
3548c2ecf20Sopenharmony_ci				  &state->ca,
3558c2ecf20Sopenharmony_ci				  /* flags */ 0,
3568c2ecf20Sopenharmony_ci				  /* n_slots */ 1);
3578c2ecf20Sopenharmony_ci	if (ret) {
3588c2ecf20Sopenharmony_ci		err("Cannot initialize CI: Error %d.", ret);
3598c2ecf20Sopenharmony_ci		memset(&state->ca, 0, sizeof(state->ca));
3608c2ecf20Sopenharmony_ci		return ret;
3618c2ecf20Sopenharmony_ci	}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	info("CI initialized.");
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	return 0;
3668c2ecf20Sopenharmony_ci}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_cistatic int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
3698c2ecf20Sopenharmony_ci{
3708c2ecf20Sopenharmony_ci	struct dvb_usb_device *d = i2c_get_adapdata(adap);
3718c2ecf20Sopenharmony_ci	static u8 obuf[60], ibuf[60];
3728c2ecf20Sopenharmony_ci	int i, write_read, read;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
3758c2ecf20Sopenharmony_ci		return -EAGAIN;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	if (num > 2)
3788c2ecf20Sopenharmony_ci		warn("more than 2 i2c messages at a time is not handled yet. TODO.");
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	for (i = 0; i < num; i++) {
3818c2ecf20Sopenharmony_ci		write_read = i+1 < num && (msg[i+1].flags & I2C_M_RD);
3828c2ecf20Sopenharmony_ci		read = msg[i].flags & I2C_M_RD;
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci		if (3 + msg[i].len > sizeof(obuf)) {
3858c2ecf20Sopenharmony_ci			err("i2c wr len=%d too high", msg[i].len);
3868c2ecf20Sopenharmony_ci			break;
3878c2ecf20Sopenharmony_ci		}
3888c2ecf20Sopenharmony_ci		if (write_read) {
3898c2ecf20Sopenharmony_ci			if (3 + msg[i+1].len > sizeof(ibuf)) {
3908c2ecf20Sopenharmony_ci				err("i2c rd len=%d too high", msg[i+1].len);
3918c2ecf20Sopenharmony_ci				break;
3928c2ecf20Sopenharmony_ci			}
3938c2ecf20Sopenharmony_ci		} else if (read) {
3948c2ecf20Sopenharmony_ci			if (3 + msg[i].len > sizeof(ibuf)) {
3958c2ecf20Sopenharmony_ci				err("i2c rd len=%d too high", msg[i].len);
3968c2ecf20Sopenharmony_ci				break;
3978c2ecf20Sopenharmony_ci			}
3988c2ecf20Sopenharmony_ci		}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci		obuf[0] = (msg[i].addr << 1) | (write_read | read);
4018c2ecf20Sopenharmony_ci		if (read)
4028c2ecf20Sopenharmony_ci			obuf[1] = 0;
4038c2ecf20Sopenharmony_ci		else
4048c2ecf20Sopenharmony_ci			obuf[1] = msg[i].len;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci		/* read request */
4078c2ecf20Sopenharmony_ci		if (write_read)
4088c2ecf20Sopenharmony_ci			obuf[2] = msg[i+1].len;
4098c2ecf20Sopenharmony_ci		else if (read)
4108c2ecf20Sopenharmony_ci			obuf[2] = msg[i].len;
4118c2ecf20Sopenharmony_ci		else
4128c2ecf20Sopenharmony_ci			obuf[2] = 0;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci		memcpy(&obuf[3], msg[i].buf, msg[i].len);
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci		if (ttusb2_msg(d, CMD_I2C_XFER, obuf, obuf[1]+3, ibuf, obuf[2] + 3) < 0) {
4178c2ecf20Sopenharmony_ci			err("i2c transfer failed.");
4188c2ecf20Sopenharmony_ci			break;
4198c2ecf20Sopenharmony_ci		}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci		if (write_read) {
4228c2ecf20Sopenharmony_ci			memcpy(msg[i+1].buf, &ibuf[3], msg[i+1].len);
4238c2ecf20Sopenharmony_ci			i++;
4248c2ecf20Sopenharmony_ci		} else if (read)
4258c2ecf20Sopenharmony_ci			memcpy(msg[i].buf, &ibuf[3], msg[i].len);
4268c2ecf20Sopenharmony_ci	}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	mutex_unlock(&d->i2c_mutex);
4298c2ecf20Sopenharmony_ci	return i;
4308c2ecf20Sopenharmony_ci}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_cistatic u32 ttusb2_i2c_func(struct i2c_adapter *adapter)
4338c2ecf20Sopenharmony_ci{
4348c2ecf20Sopenharmony_ci	return I2C_FUNC_I2C;
4358c2ecf20Sopenharmony_ci}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_cistatic struct i2c_algorithm ttusb2_i2c_algo = {
4388c2ecf20Sopenharmony_ci	.master_xfer   = ttusb2_i2c_xfer,
4398c2ecf20Sopenharmony_ci	.functionality = ttusb2_i2c_func,
4408c2ecf20Sopenharmony_ci};
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci/* command to poll IR receiver (copied from pctv452e.c) */
4438c2ecf20Sopenharmony_ci#define CMD_GET_IR_CODE     0x1b
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci/* IR */
4468c2ecf20Sopenharmony_cistatic int tt3650_rc_query(struct dvb_usb_device *d)
4478c2ecf20Sopenharmony_ci{
4488c2ecf20Sopenharmony_ci	int ret;
4498c2ecf20Sopenharmony_ci	u8 rx[9]; /* A CMD_GET_IR_CODE reply is 9 bytes long */
4508c2ecf20Sopenharmony_ci	struct ttusb2_state *st = d->priv;
4518c2ecf20Sopenharmony_ci	ret = ttusb2_msg(d, CMD_GET_IR_CODE, NULL, 0, rx, sizeof(rx));
4528c2ecf20Sopenharmony_ci	if (ret != 0)
4538c2ecf20Sopenharmony_ci		return ret;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	if (rx[8] & 0x01) {
4568c2ecf20Sopenharmony_ci		/* got a "press" event */
4578c2ecf20Sopenharmony_ci		st->last_rc_key = RC_SCANCODE_RC5(rx[3], rx[2]);
4588c2ecf20Sopenharmony_ci		deb_info("%s: cmd=0x%02x sys=0x%02x\n", __func__, rx[2], rx[3]);
4598c2ecf20Sopenharmony_ci		rc_keydown(d->rc_dev, RC_PROTO_RC5, st->last_rc_key, rx[1]);
4608c2ecf20Sopenharmony_ci	} else if (st->last_rc_key) {
4618c2ecf20Sopenharmony_ci		rc_keyup(d->rc_dev);
4628c2ecf20Sopenharmony_ci		st->last_rc_key = 0;
4638c2ecf20Sopenharmony_ci	}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	return 0;
4668c2ecf20Sopenharmony_ci}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci/* Callbacks for DVB USB */
4708c2ecf20Sopenharmony_cistatic int ttusb2_identify_state(struct usb_device *udev,
4718c2ecf20Sopenharmony_ci				 const struct dvb_usb_device_properties *props,
4728c2ecf20Sopenharmony_ci				 const struct dvb_usb_device_description **desc,
4738c2ecf20Sopenharmony_ci				 int *cold)
4748c2ecf20Sopenharmony_ci{
4758c2ecf20Sopenharmony_ci	*cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0;
4768c2ecf20Sopenharmony_ci	return 0;
4778c2ecf20Sopenharmony_ci}
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_cistatic int ttusb2_power_ctrl(struct dvb_usb_device *d, int onoff)
4808c2ecf20Sopenharmony_ci{
4818c2ecf20Sopenharmony_ci	u8 b = onoff;
4828c2ecf20Sopenharmony_ci	ttusb2_msg(d, CMD_POWER, &b, 0, NULL, 0);
4838c2ecf20Sopenharmony_ci	return ttusb2_msg(d, CMD_POWER, &b, 1, NULL, 0);
4848c2ecf20Sopenharmony_ci}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_cistatic struct tda10086_config tda10086_config = {
4888c2ecf20Sopenharmony_ci	.demod_address = 0x0e,
4898c2ecf20Sopenharmony_ci	.invert = 0,
4908c2ecf20Sopenharmony_ci	.diseqc_tone = 1,
4918c2ecf20Sopenharmony_ci	.xtal_freq = TDA10086_XTAL_16M,
4928c2ecf20Sopenharmony_ci};
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_cistatic struct tda10023_config tda10023_config = {
4958c2ecf20Sopenharmony_ci	.demod_address = 0x0c,
4968c2ecf20Sopenharmony_ci	.invert = 0,
4978c2ecf20Sopenharmony_ci	.xtal = 16000000,
4988c2ecf20Sopenharmony_ci	.pll_m = 11,
4998c2ecf20Sopenharmony_ci	.pll_p = 3,
5008c2ecf20Sopenharmony_ci	.pll_n = 1,
5018c2ecf20Sopenharmony_ci	.deltaf = 0xa511,
5028c2ecf20Sopenharmony_ci};
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_cistatic struct tda10048_config tda10048_config = {
5058c2ecf20Sopenharmony_ci	.demod_address    = 0x10 >> 1,
5068c2ecf20Sopenharmony_ci	.output_mode      = TDA10048_PARALLEL_OUTPUT,
5078c2ecf20Sopenharmony_ci	.inversion        = TDA10048_INVERSION_ON,
5088c2ecf20Sopenharmony_ci	.dtv6_if_freq_khz = TDA10048_IF_4000,
5098c2ecf20Sopenharmony_ci	.dtv7_if_freq_khz = TDA10048_IF_4500,
5108c2ecf20Sopenharmony_ci	.dtv8_if_freq_khz = TDA10048_IF_5000,
5118c2ecf20Sopenharmony_ci	.clk_freq_khz     = TDA10048_CLK_16000,
5128c2ecf20Sopenharmony_ci	.no_firmware      = 1,
5138c2ecf20Sopenharmony_ci	.set_pll          = true ,
5148c2ecf20Sopenharmony_ci	.pll_m            = 5,
5158c2ecf20Sopenharmony_ci	.pll_n            = 3,
5168c2ecf20Sopenharmony_ci	.pll_p            = 0,
5178c2ecf20Sopenharmony_ci};
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_cistatic struct tda827x_config tda827x_config = {
5208c2ecf20Sopenharmony_ci	.config = 0,
5218c2ecf20Sopenharmony_ci};
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_cistatic int ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap)
5248c2ecf20Sopenharmony_ci{
5258c2ecf20Sopenharmony_ci	if (usb_set_interface(adap->dev->udev,0,3) < 0)
5268c2ecf20Sopenharmony_ci		err("set interface to alts=3 failed");
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	if ((adap->fe_adap[0].fe = dvb_attach(tda10086_attach, &tda10086_config, &adap->dev->i2c_adap)) == NULL) {
5298c2ecf20Sopenharmony_ci		deb_info("TDA10086 attach failed\n");
5308c2ecf20Sopenharmony_ci		return -ENODEV;
5318c2ecf20Sopenharmony_ci	}
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	return 0;
5348c2ecf20Sopenharmony_ci}
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_cistatic int ttusb2_ct3650_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
5378c2ecf20Sopenharmony_ci{
5388c2ecf20Sopenharmony_ci	struct dvb_usb_adapter *adap = fe->dvb->priv;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	return adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, enable);
5418c2ecf20Sopenharmony_ci}
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_cistatic int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap)
5448c2ecf20Sopenharmony_ci{
5458c2ecf20Sopenharmony_ci	if (usb_set_interface(adap->dev->udev, 0, 3) < 0)
5468c2ecf20Sopenharmony_ci		err("set interface to alts=3 failed");
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	if (adap->fe_adap[0].fe == NULL) {
5498c2ecf20Sopenharmony_ci		/* FE 0 DVB-C */
5508c2ecf20Sopenharmony_ci		adap->fe_adap[0].fe = dvb_attach(tda10023_attach,
5518c2ecf20Sopenharmony_ci			&tda10023_config, &adap->dev->i2c_adap, 0x48);
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci		if (adap->fe_adap[0].fe == NULL) {
5548c2ecf20Sopenharmony_ci			deb_info("TDA10023 attach failed\n");
5558c2ecf20Sopenharmony_ci			return -ENODEV;
5568c2ecf20Sopenharmony_ci		}
5578c2ecf20Sopenharmony_ci		tt3650_ci_init(adap);
5588c2ecf20Sopenharmony_ci	} else {
5598c2ecf20Sopenharmony_ci		adap->fe_adap[1].fe = dvb_attach(tda10048_attach,
5608c2ecf20Sopenharmony_ci			&tda10048_config, &adap->dev->i2c_adap);
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci		if (adap->fe_adap[1].fe == NULL) {
5638c2ecf20Sopenharmony_ci			deb_info("TDA10048 attach failed\n");
5648c2ecf20Sopenharmony_ci			return -ENODEV;
5658c2ecf20Sopenharmony_ci		}
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci		/* tuner is behind TDA10023 I2C-gate */
5688c2ecf20Sopenharmony_ci		adap->fe_adap[1].fe->ops.i2c_gate_ctrl = ttusb2_ct3650_i2c_gate_ctrl;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	}
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	return 0;
5738c2ecf20Sopenharmony_ci}
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_cistatic int ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter *adap)
5768c2ecf20Sopenharmony_ci{
5778c2ecf20Sopenharmony_ci	struct dvb_frontend *fe;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	/* MFE: select correct FE to attach tuner since that's called twice */
5808c2ecf20Sopenharmony_ci	if (adap->fe_adap[1].fe == NULL)
5818c2ecf20Sopenharmony_ci		fe = adap->fe_adap[0].fe;
5828c2ecf20Sopenharmony_ci	else
5838c2ecf20Sopenharmony_ci		fe = adap->fe_adap[1].fe;
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	/* attach tuner */
5868c2ecf20Sopenharmony_ci	if (dvb_attach(tda827x_attach, fe, 0x61, &adap->dev->i2c_adap, &tda827x_config) == NULL) {
5878c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: No tda827x found!\n", __func__);
5888c2ecf20Sopenharmony_ci		return -ENODEV;
5898c2ecf20Sopenharmony_ci	}
5908c2ecf20Sopenharmony_ci	return 0;
5918c2ecf20Sopenharmony_ci}
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_cistatic int ttusb2_tuner_tda826x_attach(struct dvb_usb_adapter *adap)
5948c2ecf20Sopenharmony_ci{
5958c2ecf20Sopenharmony_ci	if (dvb_attach(tda826x_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap, 0) == NULL) {
5968c2ecf20Sopenharmony_ci		deb_info("TDA8263 attach failed\n");
5978c2ecf20Sopenharmony_ci		return -ENODEV;
5988c2ecf20Sopenharmony_ci	}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	if (dvb_attach(lnbp21_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, 0, 0) == NULL) {
6018c2ecf20Sopenharmony_ci		deb_info("LNBP21 attach failed\n");
6028c2ecf20Sopenharmony_ci		return -ENODEV;
6038c2ecf20Sopenharmony_ci	}
6048c2ecf20Sopenharmony_ci	return 0;
6058c2ecf20Sopenharmony_ci}
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci/* DVB USB Driver stuff */
6088c2ecf20Sopenharmony_cistatic struct dvb_usb_device_properties ttusb2_properties;
6098c2ecf20Sopenharmony_cistatic struct dvb_usb_device_properties ttusb2_properties_s2400;
6108c2ecf20Sopenharmony_cistatic struct dvb_usb_device_properties ttusb2_properties_ct3650;
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_cistatic void ttusb2_usb_disconnect(struct usb_interface *intf)
6138c2ecf20Sopenharmony_ci{
6148c2ecf20Sopenharmony_ci	struct dvb_usb_device *d = usb_get_intfdata(intf);
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	tt3650_ci_uninit(d);
6178c2ecf20Sopenharmony_ci	dvb_usb_device_exit(intf);
6188c2ecf20Sopenharmony_ci}
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_cistatic int ttusb2_probe(struct usb_interface *intf,
6218c2ecf20Sopenharmony_ci		const struct usb_device_id *id)
6228c2ecf20Sopenharmony_ci{
6238c2ecf20Sopenharmony_ci	if (0 == dvb_usb_device_init(intf, &ttusb2_properties,
6248c2ecf20Sopenharmony_ci				     THIS_MODULE, NULL, adapter_nr) ||
6258c2ecf20Sopenharmony_ci	    0 == dvb_usb_device_init(intf, &ttusb2_properties_s2400,
6268c2ecf20Sopenharmony_ci				     THIS_MODULE, NULL, adapter_nr) ||
6278c2ecf20Sopenharmony_ci	    0 == dvb_usb_device_init(intf, &ttusb2_properties_ct3650,
6288c2ecf20Sopenharmony_ci				     THIS_MODULE, NULL, adapter_nr))
6298c2ecf20Sopenharmony_ci		return 0;
6308c2ecf20Sopenharmony_ci	return -ENODEV;
6318c2ecf20Sopenharmony_ci}
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_cistatic struct usb_device_id ttusb2_table [] = {
6348c2ecf20Sopenharmony_ci	{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_400E) },
6358c2ecf20Sopenharmony_ci	{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_450E) },
6368c2ecf20Sopenharmony_ci	{ USB_DEVICE(USB_VID_TECHNOTREND,
6378c2ecf20Sopenharmony_ci		USB_PID_TECHNOTREND_CONNECT_S2400) },
6388c2ecf20Sopenharmony_ci	{ USB_DEVICE(USB_VID_TECHNOTREND,
6398c2ecf20Sopenharmony_ci		USB_PID_TECHNOTREND_CONNECT_CT3650) },
6408c2ecf20Sopenharmony_ci	{ USB_DEVICE(USB_VID_TECHNOTREND,
6418c2ecf20Sopenharmony_ci		USB_PID_TECHNOTREND_CONNECT_S2400_8KEEPROM) },
6428c2ecf20Sopenharmony_ci	{}		/* Terminating entry */
6438c2ecf20Sopenharmony_ci};
6448c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE (usb, ttusb2_table);
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_cistatic struct dvb_usb_device_properties ttusb2_properties = {
6478c2ecf20Sopenharmony_ci	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	.usb_ctrl = CYPRESS_FX2,
6508c2ecf20Sopenharmony_ci	.firmware = "dvb-usb-pctv-400e-01.fw",
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	.size_of_priv = sizeof(struct ttusb2_state),
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	.num_adapters = 1,
6558c2ecf20Sopenharmony_ci	.adapter = {
6568c2ecf20Sopenharmony_ci		{
6578c2ecf20Sopenharmony_ci		.num_frontends = 1,
6588c2ecf20Sopenharmony_ci		.fe = {{
6598c2ecf20Sopenharmony_ci			.streaming_ctrl   = NULL, // ttusb2_streaming_ctrl,
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci			.frontend_attach  = ttusb2_frontend_tda10086_attach,
6628c2ecf20Sopenharmony_ci			.tuner_attach     = ttusb2_tuner_tda826x_attach,
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci			/* parameter for the MPEG2-data transfer */
6658c2ecf20Sopenharmony_ci			.stream = {
6668c2ecf20Sopenharmony_ci				.type = USB_ISOC,
6678c2ecf20Sopenharmony_ci				.count = 5,
6688c2ecf20Sopenharmony_ci				.endpoint = 0x02,
6698c2ecf20Sopenharmony_ci				.u = {
6708c2ecf20Sopenharmony_ci					.isoc = {
6718c2ecf20Sopenharmony_ci						.framesperurb = 4,
6728c2ecf20Sopenharmony_ci						.framesize = 940,
6738c2ecf20Sopenharmony_ci						.interval = 1,
6748c2ecf20Sopenharmony_ci					}
6758c2ecf20Sopenharmony_ci				}
6768c2ecf20Sopenharmony_ci			}
6778c2ecf20Sopenharmony_ci		}},
6788c2ecf20Sopenharmony_ci		}
6798c2ecf20Sopenharmony_ci	},
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	.power_ctrl       = ttusb2_power_ctrl,
6828c2ecf20Sopenharmony_ci	.identify_state   = ttusb2_identify_state,
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	.i2c_algo         = &ttusb2_i2c_algo,
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x01,
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	.num_device_descs = 2,
6898c2ecf20Sopenharmony_ci	.devices = {
6908c2ecf20Sopenharmony_ci		{   "Pinnacle 400e DVB-S USB2.0",
6918c2ecf20Sopenharmony_ci			{ &ttusb2_table[0], NULL },
6928c2ecf20Sopenharmony_ci			{ NULL },
6938c2ecf20Sopenharmony_ci		},
6948c2ecf20Sopenharmony_ci		{   "Pinnacle 450e DVB-S USB2.0",
6958c2ecf20Sopenharmony_ci			{ &ttusb2_table[1], NULL },
6968c2ecf20Sopenharmony_ci			{ NULL },
6978c2ecf20Sopenharmony_ci		},
6988c2ecf20Sopenharmony_ci	}
6998c2ecf20Sopenharmony_ci};
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_cistatic struct dvb_usb_device_properties ttusb2_properties_s2400 = {
7028c2ecf20Sopenharmony_ci	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	.usb_ctrl = CYPRESS_FX2,
7058c2ecf20Sopenharmony_ci	.firmware = "dvb-usb-tt-s2400-01.fw",
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	.size_of_priv = sizeof(struct ttusb2_state),
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	.num_adapters = 1,
7108c2ecf20Sopenharmony_ci	.adapter = {
7118c2ecf20Sopenharmony_ci		{
7128c2ecf20Sopenharmony_ci		.num_frontends = 1,
7138c2ecf20Sopenharmony_ci		.fe = {{
7148c2ecf20Sopenharmony_ci			.streaming_ctrl   = NULL,
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci			.frontend_attach  = ttusb2_frontend_tda10086_attach,
7178c2ecf20Sopenharmony_ci			.tuner_attach     = ttusb2_tuner_tda826x_attach,
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci			/* parameter for the MPEG2-data transfer */
7208c2ecf20Sopenharmony_ci			.stream = {
7218c2ecf20Sopenharmony_ci				.type = USB_ISOC,
7228c2ecf20Sopenharmony_ci				.count = 5,
7238c2ecf20Sopenharmony_ci				.endpoint = 0x02,
7248c2ecf20Sopenharmony_ci				.u = {
7258c2ecf20Sopenharmony_ci					.isoc = {
7268c2ecf20Sopenharmony_ci						.framesperurb = 4,
7278c2ecf20Sopenharmony_ci						.framesize = 940,
7288c2ecf20Sopenharmony_ci						.interval = 1,
7298c2ecf20Sopenharmony_ci					}
7308c2ecf20Sopenharmony_ci				}
7318c2ecf20Sopenharmony_ci			}
7328c2ecf20Sopenharmony_ci		}},
7338c2ecf20Sopenharmony_ci		}
7348c2ecf20Sopenharmony_ci	},
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	.power_ctrl       = ttusb2_power_ctrl,
7378c2ecf20Sopenharmony_ci	.identify_state   = ttusb2_identify_state,
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	.i2c_algo         = &ttusb2_i2c_algo,
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x01,
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	.num_device_descs = 2,
7448c2ecf20Sopenharmony_ci	.devices = {
7458c2ecf20Sopenharmony_ci		{   "Technotrend TT-connect S-2400",
7468c2ecf20Sopenharmony_ci			{ &ttusb2_table[2], NULL },
7478c2ecf20Sopenharmony_ci			{ NULL },
7488c2ecf20Sopenharmony_ci		},
7498c2ecf20Sopenharmony_ci		{   "Technotrend TT-connect S-2400 (8kB EEPROM)",
7508c2ecf20Sopenharmony_ci			{ &ttusb2_table[4], NULL },
7518c2ecf20Sopenharmony_ci			{ NULL },
7528c2ecf20Sopenharmony_ci		},
7538c2ecf20Sopenharmony_ci	}
7548c2ecf20Sopenharmony_ci};
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_cistatic struct dvb_usb_device_properties ttusb2_properties_ct3650 = {
7578c2ecf20Sopenharmony_ci	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	.usb_ctrl = CYPRESS_FX2,
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	.size_of_priv = sizeof(struct ttusb2_state),
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	.rc.core = {
7648c2ecf20Sopenharmony_ci		.rc_interval      = 150, /* Less than IR_KEYPRESS_TIMEOUT */
7658c2ecf20Sopenharmony_ci		.rc_codes         = RC_MAP_TT_1500,
7668c2ecf20Sopenharmony_ci		.rc_query         = tt3650_rc_query,
7678c2ecf20Sopenharmony_ci		.allowed_protos   = RC_PROTO_BIT_RC5,
7688c2ecf20Sopenharmony_ci	},
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	.num_adapters = 1,
7718c2ecf20Sopenharmony_ci	.adapter = {
7728c2ecf20Sopenharmony_ci		{
7738c2ecf20Sopenharmony_ci		.num_frontends = 2,
7748c2ecf20Sopenharmony_ci		.fe = {{
7758c2ecf20Sopenharmony_ci			.streaming_ctrl   = NULL,
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci			.frontend_attach  = ttusb2_frontend_tda10023_attach,
7788c2ecf20Sopenharmony_ci			.tuner_attach = ttusb2_tuner_tda827x_attach,
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci			/* parameter for the MPEG2-data transfer */
7818c2ecf20Sopenharmony_ci			.stream = {
7828c2ecf20Sopenharmony_ci				.type = USB_ISOC,
7838c2ecf20Sopenharmony_ci				.count = 5,
7848c2ecf20Sopenharmony_ci				.endpoint = 0x02,
7858c2ecf20Sopenharmony_ci				.u = {
7868c2ecf20Sopenharmony_ci					.isoc = {
7878c2ecf20Sopenharmony_ci						.framesperurb = 4,
7888c2ecf20Sopenharmony_ci						.framesize = 940,
7898c2ecf20Sopenharmony_ci						.interval = 1,
7908c2ecf20Sopenharmony_ci					}
7918c2ecf20Sopenharmony_ci				}
7928c2ecf20Sopenharmony_ci			}
7938c2ecf20Sopenharmony_ci		}, {
7948c2ecf20Sopenharmony_ci			.streaming_ctrl   = NULL,
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci			.frontend_attach  = ttusb2_frontend_tda10023_attach,
7978c2ecf20Sopenharmony_ci			.tuner_attach = ttusb2_tuner_tda827x_attach,
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci			/* parameter for the MPEG2-data transfer */
8008c2ecf20Sopenharmony_ci			.stream = {
8018c2ecf20Sopenharmony_ci				.type = USB_ISOC,
8028c2ecf20Sopenharmony_ci				.count = 5,
8038c2ecf20Sopenharmony_ci				.endpoint = 0x02,
8048c2ecf20Sopenharmony_ci				.u = {
8058c2ecf20Sopenharmony_ci					.isoc = {
8068c2ecf20Sopenharmony_ci						.framesperurb = 4,
8078c2ecf20Sopenharmony_ci						.framesize = 940,
8088c2ecf20Sopenharmony_ci						.interval = 1,
8098c2ecf20Sopenharmony_ci					}
8108c2ecf20Sopenharmony_ci				}
8118c2ecf20Sopenharmony_ci			}
8128c2ecf20Sopenharmony_ci		}},
8138c2ecf20Sopenharmony_ci		},
8148c2ecf20Sopenharmony_ci	},
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci	.power_ctrl       = ttusb2_power_ctrl,
8178c2ecf20Sopenharmony_ci	.identify_state   = ttusb2_identify_state,
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci	.i2c_algo         = &ttusb2_i2c_algo,
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x01,
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	.num_device_descs = 1,
8248c2ecf20Sopenharmony_ci	.devices = {
8258c2ecf20Sopenharmony_ci		{   "Technotrend TT-connect CT-3650",
8268c2ecf20Sopenharmony_ci			.warm_ids = { &ttusb2_table[3], NULL },
8278c2ecf20Sopenharmony_ci		},
8288c2ecf20Sopenharmony_ci	}
8298c2ecf20Sopenharmony_ci};
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_cistatic struct usb_driver ttusb2_driver = {
8328c2ecf20Sopenharmony_ci	.name		= "dvb_usb_ttusb2",
8338c2ecf20Sopenharmony_ci	.probe		= ttusb2_probe,
8348c2ecf20Sopenharmony_ci	.disconnect	= ttusb2_usb_disconnect,
8358c2ecf20Sopenharmony_ci	.id_table	= ttusb2_table,
8368c2ecf20Sopenharmony_ci};
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_cimodule_usb_driver(ttusb2_driver);
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ciMODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
8418c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Driver for Pinnacle PCTV 400e DVB-S USB2.0");
8428c2ecf20Sopenharmony_ciMODULE_VERSION("1.0");
8438c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
844