xref: /linux/drivers/media/usb/dvb-usb/ttusb2.c (revision 577a7ad33aeff86f6c97277b12b122a0a2ad97d7)
1a10e763bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2786baecfSMauro Carvalho Chehab /* DVB USB compliant linux driver for Technotrend DVB USB boxes and clones
3786baecfSMauro Carvalho Chehab  * (e.g. Pinnacle 400e DVB-S USB2.0).
4786baecfSMauro Carvalho Chehab  *
5786baecfSMauro Carvalho Chehab  * The Pinnacle 400e uses the same protocol as the Technotrend USB1.1 boxes.
6786baecfSMauro Carvalho Chehab  *
7786baecfSMauro Carvalho Chehab  * TDA8263 + TDA10086
8786baecfSMauro Carvalho Chehab  *
9786baecfSMauro Carvalho Chehab  * I2C addresses:
10786baecfSMauro Carvalho Chehab  * 0x08 - LNBP21PD   - LNB power supply
11786baecfSMauro Carvalho Chehab  * 0x0e - TDA10086   - Demodulator
12786baecfSMauro Carvalho Chehab  * 0x50 - FX2 eeprom
13786baecfSMauro Carvalho Chehab  * 0x60 - TDA8263    - Tuner
14786baecfSMauro Carvalho Chehab  * 0x78 ???
15786baecfSMauro Carvalho Chehab  *
16786baecfSMauro Carvalho Chehab  * Copyright (c) 2002 Holger Waechtler <holger@convergence.de>
17786baecfSMauro Carvalho Chehab  * Copyright (c) 2003 Felix Domke <tmbinc@elitedvb.net>
18786baecfSMauro Carvalho Chehab  * Copyright (C) 2005-6 Patrick Boettcher <pb@linuxtv.org>
19786baecfSMauro Carvalho Chehab  *
20*577a7ad3SMauro Carvalho Chehab  * see Documentation/driver-api/media/drivers/dvb-usb.rst for more information
21786baecfSMauro Carvalho Chehab  */
22786baecfSMauro Carvalho Chehab #define DVB_USB_LOG_PREFIX "ttusb2"
23786baecfSMauro Carvalho Chehab #include "dvb-usb.h"
24786baecfSMauro Carvalho Chehab 
25786baecfSMauro Carvalho Chehab #include "ttusb2.h"
26786baecfSMauro Carvalho Chehab 
27786baecfSMauro Carvalho Chehab #include "tda826x.h"
28786baecfSMauro Carvalho Chehab #include "tda10086.h"
29786baecfSMauro Carvalho Chehab #include "tda1002x.h"
30786baecfSMauro Carvalho Chehab #include "tda10048.h"
31786baecfSMauro Carvalho Chehab #include "tda827x.h"
32786baecfSMauro Carvalho Chehab #include "lnbp21.h"
33786baecfSMauro Carvalho Chehab /* CA */
34fada1935SMauro Carvalho Chehab #include <media/dvb_ca_en50221.h>
35786baecfSMauro Carvalho Chehab 
36786baecfSMauro Carvalho Chehab /* debug */
37786baecfSMauro Carvalho Chehab static int dvb_usb_ttusb2_debug;
38786baecfSMauro Carvalho Chehab #define deb_info(args...)   dprintk(dvb_usb_ttusb2_debug,0x01,args)
39786baecfSMauro Carvalho Chehab module_param_named(debug,dvb_usb_ttusb2_debug, int, 0644);
40786baecfSMauro Carvalho Chehab MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))." DVB_USB_DEBUG_STATUS);
41786baecfSMauro Carvalho Chehab static int dvb_usb_ttusb2_debug_ci;
42786baecfSMauro Carvalho Chehab module_param_named(debug_ci,dvb_usb_ttusb2_debug_ci, int, 0644);
43786baecfSMauro Carvalho Chehab MODULE_PARM_DESC(debug_ci, "set debugging ci." DVB_USB_DEBUG_STATUS);
44786baecfSMauro Carvalho Chehab 
45786baecfSMauro Carvalho Chehab DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
46786baecfSMauro Carvalho Chehab 
47786baecfSMauro Carvalho Chehab #define ci_dbg(format, arg...)                \
48786baecfSMauro Carvalho Chehab do {                                          \
49786baecfSMauro Carvalho Chehab 	if (dvb_usb_ttusb2_debug_ci)                                    \
50786baecfSMauro Carvalho Chehab 		printk(KERN_DEBUG DVB_USB_LOG_PREFIX \
51786baecfSMauro Carvalho Chehab 			": %s " format "\n" , __func__, ## arg);       \
52786baecfSMauro Carvalho Chehab } while (0)
53786baecfSMauro Carvalho Chehab 
54786baecfSMauro Carvalho Chehab enum {
55786baecfSMauro Carvalho Chehab 	TT3650_CMD_CI_TEST = 0x40,
56786baecfSMauro Carvalho Chehab 	TT3650_CMD_CI_RD_CTRL,
57786baecfSMauro Carvalho Chehab 	TT3650_CMD_CI_WR_CTRL,
58786baecfSMauro Carvalho Chehab 	TT3650_CMD_CI_RD_ATTR,
59786baecfSMauro Carvalho Chehab 	TT3650_CMD_CI_WR_ATTR,
60786baecfSMauro Carvalho Chehab 	TT3650_CMD_CI_RESET,
61786baecfSMauro Carvalho Chehab 	TT3650_CMD_CI_SET_VIDEO_PORT
62786baecfSMauro Carvalho Chehab };
63786baecfSMauro Carvalho Chehab 
64786baecfSMauro Carvalho Chehab struct ttusb2_state {
65786baecfSMauro Carvalho Chehab 	struct dvb_ca_en50221 ca;
66786baecfSMauro Carvalho Chehab 	struct mutex ca_mutex;
67786baecfSMauro Carvalho Chehab 	u8 id;
68786baecfSMauro Carvalho Chehab 	u16 last_rc_key;
69786baecfSMauro Carvalho Chehab };
70786baecfSMauro Carvalho Chehab 
71786baecfSMauro Carvalho Chehab static int ttusb2_msg(struct dvb_usb_device *d, u8 cmd,
72786baecfSMauro Carvalho Chehab 		u8 *wbuf, int wlen, u8 *rbuf, int rlen)
73786baecfSMauro Carvalho Chehab {
74786baecfSMauro Carvalho Chehab 	struct ttusb2_state *st = d->priv;
75786baecfSMauro Carvalho Chehab 	u8 *s, *r = NULL;
76786baecfSMauro Carvalho Chehab 	int ret = 0;
77786baecfSMauro Carvalho Chehab 
78a12b8ab8SAlyssa Milburn 	if (4 + rlen > 64)
79a12b8ab8SAlyssa Milburn 		return -EIO;
80a12b8ab8SAlyssa Milburn 
81786baecfSMauro Carvalho Chehab 	s = kzalloc(wlen+4, GFP_KERNEL);
82786baecfSMauro Carvalho Chehab 	if (!s)
83786baecfSMauro Carvalho Chehab 		return -ENOMEM;
84786baecfSMauro Carvalho Chehab 
85786baecfSMauro Carvalho Chehab 	r = kzalloc(64, GFP_KERNEL);
86786baecfSMauro Carvalho Chehab 	if (!r) {
87786baecfSMauro Carvalho Chehab 		kfree(s);
88786baecfSMauro Carvalho Chehab 		return -ENOMEM;
89786baecfSMauro Carvalho Chehab 	}
90786baecfSMauro Carvalho Chehab 
91786baecfSMauro Carvalho Chehab 	s[0] = 0xaa;
92786baecfSMauro Carvalho Chehab 	s[1] = ++st->id;
93786baecfSMauro Carvalho Chehab 	s[2] = cmd;
94786baecfSMauro Carvalho Chehab 	s[3] = wlen;
95786baecfSMauro Carvalho Chehab 	memcpy(&s[4],wbuf,wlen);
96786baecfSMauro Carvalho Chehab 
97786baecfSMauro Carvalho Chehab 	ret = dvb_usb_generic_rw(d, s, wlen+4, r, 64, 0);
98786baecfSMauro Carvalho Chehab 
99786baecfSMauro Carvalho Chehab 	if (ret  != 0 ||
100786baecfSMauro Carvalho Chehab 		r[0] != 0x55 ||
101786baecfSMauro Carvalho Chehab 		r[1] != s[1] ||
102786baecfSMauro Carvalho Chehab 		r[2] != cmd ||
103786baecfSMauro Carvalho Chehab 		(rlen > 0 && r[3] != rlen)) {
104786baecfSMauro Carvalho Chehab 		warn("there might have been an error during control message transfer. (rlen = %d, was %d)",rlen,r[3]);
105786baecfSMauro Carvalho Chehab 		kfree(s);
106786baecfSMauro Carvalho Chehab 		kfree(r);
107786baecfSMauro Carvalho Chehab 		return -EIO;
108786baecfSMauro Carvalho Chehab 	}
109786baecfSMauro Carvalho Chehab 
110786baecfSMauro Carvalho Chehab 	if (rlen > 0)
111786baecfSMauro Carvalho Chehab 		memcpy(rbuf, &r[4], rlen);
112786baecfSMauro Carvalho Chehab 
113786baecfSMauro Carvalho Chehab 	kfree(s);
114786baecfSMauro Carvalho Chehab 	kfree(r);
115786baecfSMauro Carvalho Chehab 
116786baecfSMauro Carvalho Chehab 	return 0;
117786baecfSMauro Carvalho Chehab }
118786baecfSMauro Carvalho Chehab 
119786baecfSMauro Carvalho Chehab /* ci */
120786baecfSMauro Carvalho Chehab static int tt3650_ci_msg(struct dvb_usb_device *d, u8 cmd, u8 *data, unsigned int write_len, unsigned int read_len)
121786baecfSMauro Carvalho Chehab {
122786baecfSMauro Carvalho Chehab 	int ret;
123786baecfSMauro Carvalho Chehab 	u8 rx[60];/* (64 -4) */
124786baecfSMauro Carvalho Chehab 	ret = ttusb2_msg(d, cmd, data, write_len, rx, read_len);
125786baecfSMauro Carvalho Chehab 	if (!ret)
126786baecfSMauro Carvalho Chehab 		memcpy(data, rx, read_len);
127786baecfSMauro Carvalho Chehab 	return ret;
128786baecfSMauro Carvalho Chehab }
129786baecfSMauro Carvalho Chehab 
130786baecfSMauro Carvalho Chehab static int tt3650_ci_msg_locked(struct dvb_ca_en50221 *ca, u8 cmd, u8 *data, unsigned int write_len, unsigned int read_len)
131786baecfSMauro Carvalho Chehab {
132786baecfSMauro Carvalho Chehab 	struct dvb_usb_device *d = ca->data;
133786baecfSMauro Carvalho Chehab 	struct ttusb2_state *state = d->priv;
134786baecfSMauro Carvalho Chehab 	int ret;
135786baecfSMauro Carvalho Chehab 
136786baecfSMauro Carvalho Chehab 	mutex_lock(&state->ca_mutex);
137786baecfSMauro Carvalho Chehab 	ret = tt3650_ci_msg(d, cmd, data, write_len, read_len);
138786baecfSMauro Carvalho Chehab 	mutex_unlock(&state->ca_mutex);
139786baecfSMauro Carvalho Chehab 
140786baecfSMauro Carvalho Chehab 	return ret;
141786baecfSMauro Carvalho Chehab }
142786baecfSMauro Carvalho Chehab 
143786baecfSMauro Carvalho Chehab static int tt3650_ci_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
144786baecfSMauro Carvalho Chehab {
145786baecfSMauro Carvalho Chehab 	u8 buf[3];
146786baecfSMauro Carvalho Chehab 	int ret = 0;
147786baecfSMauro Carvalho Chehab 
148786baecfSMauro Carvalho Chehab 	if (slot)
149786baecfSMauro Carvalho Chehab 		return -EINVAL;
150786baecfSMauro Carvalho Chehab 
151786baecfSMauro Carvalho Chehab 	buf[0] = (address >> 8) & 0x0F;
152786baecfSMauro Carvalho Chehab 	buf[1] = address;
153786baecfSMauro Carvalho Chehab 
154786baecfSMauro Carvalho Chehab 
155786baecfSMauro Carvalho Chehab 	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_ATTR, buf, 2, 3);
156786baecfSMauro Carvalho Chehab 
157786baecfSMauro Carvalho Chehab 	ci_dbg("%04x -> %d 0x%02x", address, ret, buf[2]);
158786baecfSMauro Carvalho Chehab 
159786baecfSMauro Carvalho Chehab 	if (ret < 0)
160786baecfSMauro Carvalho Chehab 		return ret;
161786baecfSMauro Carvalho Chehab 
162786baecfSMauro Carvalho Chehab 	return buf[2];
163786baecfSMauro Carvalho Chehab }
164786baecfSMauro Carvalho Chehab 
165786baecfSMauro Carvalho Chehab static int tt3650_ci_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
166786baecfSMauro Carvalho Chehab {
167786baecfSMauro Carvalho Chehab 	u8 buf[3];
168786baecfSMauro Carvalho Chehab 
169786baecfSMauro Carvalho Chehab 	ci_dbg("%d 0x%04x 0x%02x", slot, address, value);
170786baecfSMauro Carvalho Chehab 
171786baecfSMauro Carvalho Chehab 	if (slot)
172786baecfSMauro Carvalho Chehab 		return -EINVAL;
173786baecfSMauro Carvalho Chehab 
174786baecfSMauro Carvalho Chehab 	buf[0] = (address >> 8) & 0x0F;
175786baecfSMauro Carvalho Chehab 	buf[1] = address;
176786baecfSMauro Carvalho Chehab 	buf[2] = value;
177786baecfSMauro Carvalho Chehab 
178786baecfSMauro Carvalho Chehab 	return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_ATTR, buf, 3, 3);
179786baecfSMauro Carvalho Chehab }
180786baecfSMauro Carvalho Chehab 
181786baecfSMauro Carvalho Chehab static int tt3650_ci_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
182786baecfSMauro Carvalho Chehab {
183786baecfSMauro Carvalho Chehab 	u8 buf[2];
184786baecfSMauro Carvalho Chehab 	int ret;
185786baecfSMauro Carvalho Chehab 
186786baecfSMauro Carvalho Chehab 	if (slot)
187786baecfSMauro Carvalho Chehab 		return -EINVAL;
188786baecfSMauro Carvalho Chehab 
189786baecfSMauro Carvalho Chehab 	buf[0] = address & 3;
190786baecfSMauro Carvalho Chehab 
191786baecfSMauro Carvalho Chehab 	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_CTRL, buf, 1, 2);
192786baecfSMauro Carvalho Chehab 
193786baecfSMauro Carvalho Chehab 	ci_dbg("0x%02x -> %d 0x%02x", address, ret, buf[1]);
194786baecfSMauro Carvalho Chehab 
195786baecfSMauro Carvalho Chehab 	if (ret < 0)
196786baecfSMauro Carvalho Chehab 		return ret;
197786baecfSMauro Carvalho Chehab 
198786baecfSMauro Carvalho Chehab 	return buf[1];
199786baecfSMauro Carvalho Chehab }
200786baecfSMauro Carvalho Chehab 
201786baecfSMauro Carvalho Chehab static int tt3650_ci_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
202786baecfSMauro Carvalho Chehab {
203786baecfSMauro Carvalho Chehab 	u8 buf[2];
204786baecfSMauro Carvalho Chehab 
205786baecfSMauro Carvalho Chehab 	ci_dbg("%d 0x%02x 0x%02x", slot, address, value);
206786baecfSMauro Carvalho Chehab 
207786baecfSMauro Carvalho Chehab 	if (slot)
208786baecfSMauro Carvalho Chehab 		return -EINVAL;
209786baecfSMauro Carvalho Chehab 
210786baecfSMauro Carvalho Chehab 	buf[0] = address;
211786baecfSMauro Carvalho Chehab 	buf[1] = value;
212786baecfSMauro Carvalho Chehab 
213786baecfSMauro Carvalho Chehab 	return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_CTRL, buf, 2, 2);
214786baecfSMauro Carvalho Chehab }
215786baecfSMauro Carvalho Chehab 
216786baecfSMauro Carvalho Chehab static int tt3650_ci_set_video_port(struct dvb_ca_en50221 *ca, int slot, int enable)
217786baecfSMauro Carvalho Chehab {
218786baecfSMauro Carvalho Chehab 	u8 buf[1];
219786baecfSMauro Carvalho Chehab 	int ret;
220786baecfSMauro Carvalho Chehab 
221786baecfSMauro Carvalho Chehab 	ci_dbg("%d %d", slot, enable);
222786baecfSMauro Carvalho Chehab 
223786baecfSMauro Carvalho Chehab 	if (slot)
224786baecfSMauro Carvalho Chehab 		return -EINVAL;
225786baecfSMauro Carvalho Chehab 
226786baecfSMauro Carvalho Chehab 	buf[0] = enable;
227786baecfSMauro Carvalho Chehab 
228786baecfSMauro Carvalho Chehab 	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
229786baecfSMauro Carvalho Chehab 	if (ret < 0)
230786baecfSMauro Carvalho Chehab 		return ret;
231786baecfSMauro Carvalho Chehab 
232786baecfSMauro Carvalho Chehab 	if (enable != buf[0]) {
233786baecfSMauro Carvalho Chehab 		err("CI not %sabled.", enable ? "en" : "dis");
234786baecfSMauro Carvalho Chehab 		return -EIO;
235786baecfSMauro Carvalho Chehab 	}
236786baecfSMauro Carvalho Chehab 
237786baecfSMauro Carvalho Chehab 	return 0;
238786baecfSMauro Carvalho Chehab }
239786baecfSMauro Carvalho Chehab 
240786baecfSMauro Carvalho Chehab static int tt3650_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
241786baecfSMauro Carvalho Chehab {
242786baecfSMauro Carvalho Chehab 	return tt3650_ci_set_video_port(ca, slot, 0);
243786baecfSMauro Carvalho Chehab }
244786baecfSMauro Carvalho Chehab 
245786baecfSMauro Carvalho Chehab static int tt3650_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
246786baecfSMauro Carvalho Chehab {
247786baecfSMauro Carvalho Chehab 	return tt3650_ci_set_video_port(ca, slot, 1);
248786baecfSMauro Carvalho Chehab }
249786baecfSMauro Carvalho Chehab 
250786baecfSMauro Carvalho Chehab static int tt3650_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
251786baecfSMauro Carvalho Chehab {
252786baecfSMauro Carvalho Chehab 	struct dvb_usb_device *d = ca->data;
253786baecfSMauro Carvalho Chehab 	struct ttusb2_state *state = d->priv;
254786baecfSMauro Carvalho Chehab 	u8 buf[1];
255786baecfSMauro Carvalho Chehab 	int ret;
256786baecfSMauro Carvalho Chehab 
257786baecfSMauro Carvalho Chehab 	ci_dbg("%d", slot);
258786baecfSMauro Carvalho Chehab 
259786baecfSMauro Carvalho Chehab 	if (slot)
260786baecfSMauro Carvalho Chehab 		return -EINVAL;
261786baecfSMauro Carvalho Chehab 
262786baecfSMauro Carvalho Chehab 	buf[0] = 0;
263786baecfSMauro Carvalho Chehab 
264786baecfSMauro Carvalho Chehab 	mutex_lock(&state->ca_mutex);
265786baecfSMauro Carvalho Chehab 
266786baecfSMauro Carvalho Chehab 	ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
267786baecfSMauro Carvalho Chehab 	if (ret)
268786baecfSMauro Carvalho Chehab 		goto failed;
269786baecfSMauro Carvalho Chehab 
270786baecfSMauro Carvalho Chehab 	msleep(500);
271786baecfSMauro Carvalho Chehab 
272786baecfSMauro Carvalho Chehab 	buf[0] = 1;
273786baecfSMauro Carvalho Chehab 
274786baecfSMauro Carvalho Chehab 	ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1);
275786baecfSMauro Carvalho Chehab 	if (ret)
276786baecfSMauro Carvalho Chehab 		goto failed;
277786baecfSMauro Carvalho Chehab 
278786baecfSMauro Carvalho Chehab 	msleep(500);
279786baecfSMauro Carvalho Chehab 
280786baecfSMauro Carvalho Chehab 	buf[0] = 0; /* FTA */
281786baecfSMauro Carvalho Chehab 
282786baecfSMauro Carvalho Chehab 	ret = tt3650_ci_msg(d, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1);
283786baecfSMauro Carvalho Chehab 
284786baecfSMauro Carvalho Chehab 	msleep(1100);
285786baecfSMauro Carvalho Chehab 
286786baecfSMauro Carvalho Chehab  failed:
287786baecfSMauro Carvalho Chehab 	mutex_unlock(&state->ca_mutex);
288786baecfSMauro Carvalho Chehab 
289786baecfSMauro Carvalho Chehab 	return ret;
290786baecfSMauro Carvalho Chehab }
291786baecfSMauro Carvalho Chehab 
292786baecfSMauro Carvalho Chehab static int tt3650_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
293786baecfSMauro Carvalho Chehab {
294786baecfSMauro Carvalho Chehab 	u8 buf[1];
295786baecfSMauro Carvalho Chehab 	int ret;
296786baecfSMauro Carvalho Chehab 
297786baecfSMauro Carvalho Chehab 	if (slot)
298786baecfSMauro Carvalho Chehab 		return -EINVAL;
299786baecfSMauro Carvalho Chehab 
300786baecfSMauro Carvalho Chehab 	ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_TEST, buf, 0, 1);
301786baecfSMauro Carvalho Chehab 	if (ret)
302786baecfSMauro Carvalho Chehab 		return ret;
303786baecfSMauro Carvalho Chehab 
304786baecfSMauro Carvalho Chehab 	if (1 == buf[0]) {
305786baecfSMauro Carvalho Chehab 		return DVB_CA_EN50221_POLL_CAM_PRESENT |
306786baecfSMauro Carvalho Chehab 			DVB_CA_EN50221_POLL_CAM_READY;
307786baecfSMauro Carvalho Chehab 	}
308786baecfSMauro Carvalho Chehab 	return 0;
309786baecfSMauro Carvalho Chehab }
310786baecfSMauro Carvalho Chehab 
311786baecfSMauro Carvalho Chehab static void tt3650_ci_uninit(struct dvb_usb_device *d)
312786baecfSMauro Carvalho Chehab {
313786baecfSMauro Carvalho Chehab 	struct ttusb2_state *state;
314786baecfSMauro Carvalho Chehab 
315786baecfSMauro Carvalho Chehab 	ci_dbg("");
316786baecfSMauro Carvalho Chehab 
317786baecfSMauro Carvalho Chehab 	if (NULL == d)
318786baecfSMauro Carvalho Chehab 		return;
319786baecfSMauro Carvalho Chehab 
320786baecfSMauro Carvalho Chehab 	state = d->priv;
321786baecfSMauro Carvalho Chehab 	if (NULL == state)
322786baecfSMauro Carvalho Chehab 		return;
323786baecfSMauro Carvalho Chehab 
324786baecfSMauro Carvalho Chehab 	if (NULL == state->ca.data)
325786baecfSMauro Carvalho Chehab 		return;
326786baecfSMauro Carvalho Chehab 
327786baecfSMauro Carvalho Chehab 	dvb_ca_en50221_release(&state->ca);
328786baecfSMauro Carvalho Chehab 
329786baecfSMauro Carvalho Chehab 	memset(&state->ca, 0, sizeof(state->ca));
330786baecfSMauro Carvalho Chehab }
331786baecfSMauro Carvalho Chehab 
332786baecfSMauro Carvalho Chehab static int tt3650_ci_init(struct dvb_usb_adapter *a)
333786baecfSMauro Carvalho Chehab {
334786baecfSMauro Carvalho Chehab 	struct dvb_usb_device *d = a->dev;
335786baecfSMauro Carvalho Chehab 	struct ttusb2_state *state = d->priv;
336786baecfSMauro Carvalho Chehab 	int ret;
337786baecfSMauro Carvalho Chehab 
338786baecfSMauro Carvalho Chehab 	ci_dbg("");
339786baecfSMauro Carvalho Chehab 
340786baecfSMauro Carvalho Chehab 	mutex_init(&state->ca_mutex);
341786baecfSMauro Carvalho Chehab 
342786baecfSMauro Carvalho Chehab 	state->ca.owner = THIS_MODULE;
343786baecfSMauro Carvalho Chehab 	state->ca.read_attribute_mem = tt3650_ci_read_attribute_mem;
344786baecfSMauro Carvalho Chehab 	state->ca.write_attribute_mem = tt3650_ci_write_attribute_mem;
345786baecfSMauro Carvalho Chehab 	state->ca.read_cam_control = tt3650_ci_read_cam_control;
346786baecfSMauro Carvalho Chehab 	state->ca.write_cam_control = tt3650_ci_write_cam_control;
347786baecfSMauro Carvalho Chehab 	state->ca.slot_reset = tt3650_ci_slot_reset;
348786baecfSMauro Carvalho Chehab 	state->ca.slot_shutdown = tt3650_ci_slot_shutdown;
349786baecfSMauro Carvalho Chehab 	state->ca.slot_ts_enable = tt3650_ci_slot_ts_enable;
350786baecfSMauro Carvalho Chehab 	state->ca.poll_slot_status = tt3650_ci_poll_slot_status;
351786baecfSMauro Carvalho Chehab 	state->ca.data = d;
352786baecfSMauro Carvalho Chehab 
353786baecfSMauro Carvalho Chehab 	ret = dvb_ca_en50221_init(&a->dvb_adap,
354786baecfSMauro Carvalho Chehab 				  &state->ca,
355786baecfSMauro Carvalho Chehab 				  /* flags */ 0,
356786baecfSMauro Carvalho Chehab 				  /* n_slots */ 1);
357786baecfSMauro Carvalho Chehab 	if (ret) {
358786baecfSMauro Carvalho Chehab 		err("Cannot initialize CI: Error %d.", ret);
359786baecfSMauro Carvalho Chehab 		memset(&state->ca, 0, sizeof(state->ca));
360786baecfSMauro Carvalho Chehab 		return ret;
361786baecfSMauro Carvalho Chehab 	}
362786baecfSMauro Carvalho Chehab 
363786baecfSMauro Carvalho Chehab 	info("CI initialized.");
364786baecfSMauro Carvalho Chehab 
365786baecfSMauro Carvalho Chehab 	return 0;
366786baecfSMauro Carvalho Chehab }
367786baecfSMauro Carvalho Chehab 
368786baecfSMauro Carvalho Chehab static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
369786baecfSMauro Carvalho Chehab {
370786baecfSMauro Carvalho Chehab 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
371786baecfSMauro Carvalho Chehab 	static u8 obuf[60], ibuf[60];
372786baecfSMauro Carvalho Chehab 	int i, write_read, read;
373786baecfSMauro Carvalho Chehab 
374786baecfSMauro Carvalho Chehab 	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
375786baecfSMauro Carvalho Chehab 		return -EAGAIN;
376786baecfSMauro Carvalho Chehab 
377786baecfSMauro Carvalho Chehab 	if (num > 2)
378786baecfSMauro Carvalho Chehab 		warn("more than 2 i2c messages at a time is not handled yet. TODO.");
379786baecfSMauro Carvalho Chehab 
380786baecfSMauro Carvalho Chehab 	for (i = 0; i < num; i++) {
381786baecfSMauro Carvalho Chehab 		write_read = i+1 < num && (msg[i+1].flags & I2C_M_RD);
382786baecfSMauro Carvalho Chehab 		read = msg[i].flags & I2C_M_RD;
383786baecfSMauro Carvalho Chehab 
384a12b8ab8SAlyssa Milburn 		if (3 + msg[i].len > sizeof(obuf)) {
385a12b8ab8SAlyssa Milburn 			err("i2c wr len=%d too high", msg[i].len);
386a12b8ab8SAlyssa Milburn 			break;
387a12b8ab8SAlyssa Milburn 		}
388a12b8ab8SAlyssa Milburn 		if (write_read) {
389a12b8ab8SAlyssa Milburn 			if (3 + msg[i+1].len > sizeof(ibuf)) {
390a12b8ab8SAlyssa Milburn 				err("i2c rd len=%d too high", msg[i+1].len);
391a12b8ab8SAlyssa Milburn 				break;
392a12b8ab8SAlyssa Milburn 			}
393a12b8ab8SAlyssa Milburn 		} else if (read) {
394a12b8ab8SAlyssa Milburn 			if (3 + msg[i].len > sizeof(ibuf)) {
395a12b8ab8SAlyssa Milburn 				err("i2c rd len=%d too high", msg[i].len);
396a12b8ab8SAlyssa Milburn 				break;
397a12b8ab8SAlyssa Milburn 			}
398a12b8ab8SAlyssa Milburn 		}
399a12b8ab8SAlyssa Milburn 
400786baecfSMauro Carvalho Chehab 		obuf[0] = (msg[i].addr << 1) | (write_read | read);
401786baecfSMauro Carvalho Chehab 		if (read)
402786baecfSMauro Carvalho Chehab 			obuf[1] = 0;
403786baecfSMauro Carvalho Chehab 		else
404786baecfSMauro Carvalho Chehab 			obuf[1] = msg[i].len;
405786baecfSMauro Carvalho Chehab 
406786baecfSMauro Carvalho Chehab 		/* read request */
407786baecfSMauro Carvalho Chehab 		if (write_read)
408786baecfSMauro Carvalho Chehab 			obuf[2] = msg[i+1].len;
409786baecfSMauro Carvalho Chehab 		else if (read)
410786baecfSMauro Carvalho Chehab 			obuf[2] = msg[i].len;
411786baecfSMauro Carvalho Chehab 		else
412786baecfSMauro Carvalho Chehab 			obuf[2] = 0;
413786baecfSMauro Carvalho Chehab 
414786baecfSMauro Carvalho Chehab 		memcpy(&obuf[3], msg[i].buf, msg[i].len);
415786baecfSMauro Carvalho Chehab 
416786baecfSMauro Carvalho Chehab 		if (ttusb2_msg(d, CMD_I2C_XFER, obuf, obuf[1]+3, ibuf, obuf[2] + 3) < 0) {
417786baecfSMauro Carvalho Chehab 			err("i2c transfer failed.");
418786baecfSMauro Carvalho Chehab 			break;
419786baecfSMauro Carvalho Chehab 		}
420786baecfSMauro Carvalho Chehab 
421786baecfSMauro Carvalho Chehab 		if (write_read) {
422786baecfSMauro Carvalho Chehab 			memcpy(msg[i+1].buf, &ibuf[3], msg[i+1].len);
423786baecfSMauro Carvalho Chehab 			i++;
424786baecfSMauro Carvalho Chehab 		} else if (read)
425786baecfSMauro Carvalho Chehab 			memcpy(msg[i].buf, &ibuf[3], msg[i].len);
426786baecfSMauro Carvalho Chehab 	}
427786baecfSMauro Carvalho Chehab 
428786baecfSMauro Carvalho Chehab 	mutex_unlock(&d->i2c_mutex);
429786baecfSMauro Carvalho Chehab 	return i;
430786baecfSMauro Carvalho Chehab }
431786baecfSMauro Carvalho Chehab 
432786baecfSMauro Carvalho Chehab static u32 ttusb2_i2c_func(struct i2c_adapter *adapter)
433786baecfSMauro Carvalho Chehab {
434786baecfSMauro Carvalho Chehab 	return I2C_FUNC_I2C;
435786baecfSMauro Carvalho Chehab }
436786baecfSMauro Carvalho Chehab 
437786baecfSMauro Carvalho Chehab static struct i2c_algorithm ttusb2_i2c_algo = {
438786baecfSMauro Carvalho Chehab 	.master_xfer   = ttusb2_i2c_xfer,
439786baecfSMauro Carvalho Chehab 	.functionality = ttusb2_i2c_func,
440786baecfSMauro Carvalho Chehab };
441786baecfSMauro Carvalho Chehab 
442786baecfSMauro Carvalho Chehab /* command to poll IR receiver (copied from pctv452e.c) */
443786baecfSMauro Carvalho Chehab #define CMD_GET_IR_CODE     0x1b
444786baecfSMauro Carvalho Chehab 
445786baecfSMauro Carvalho Chehab /* IR */
446786baecfSMauro Carvalho Chehab static int tt3650_rc_query(struct dvb_usb_device *d)
447786baecfSMauro Carvalho Chehab {
448786baecfSMauro Carvalho Chehab 	int ret;
449786baecfSMauro Carvalho Chehab 	u8 rx[9]; /* A CMD_GET_IR_CODE reply is 9 bytes long */
450786baecfSMauro Carvalho Chehab 	struct ttusb2_state *st = d->priv;
451786baecfSMauro Carvalho Chehab 	ret = ttusb2_msg(d, CMD_GET_IR_CODE, NULL, 0, rx, sizeof(rx));
452786baecfSMauro Carvalho Chehab 	if (ret != 0)
453786baecfSMauro Carvalho Chehab 		return ret;
454786baecfSMauro Carvalho Chehab 
455786baecfSMauro Carvalho Chehab 	if (rx[8] & 0x01) {
456786baecfSMauro Carvalho Chehab 		/* got a "press" event */
457120703f9SDavid Härdeman 		st->last_rc_key = RC_SCANCODE_RC5(rx[3], rx[2]);
458786baecfSMauro Carvalho Chehab 		deb_info("%s: cmd=0x%02x sys=0x%02x\n", __func__, rx[2], rx[3]);
4596d741bfeSSean Young 		rc_keydown(d->rc_dev, RC_PROTO_RC5, st->last_rc_key, rx[1]);
460786baecfSMauro Carvalho Chehab 	} else if (st->last_rc_key) {
461786baecfSMauro Carvalho Chehab 		rc_keyup(d->rc_dev);
462786baecfSMauro Carvalho Chehab 		st->last_rc_key = 0;
463786baecfSMauro Carvalho Chehab 	}
464786baecfSMauro Carvalho Chehab 
465786baecfSMauro Carvalho Chehab 	return 0;
466786baecfSMauro Carvalho Chehab }
467786baecfSMauro Carvalho Chehab 
468786baecfSMauro Carvalho Chehab 
469786baecfSMauro Carvalho Chehab /* Callbacks for DVB USB */
470786baecfSMauro Carvalho Chehab static int ttusb2_identify_state (struct usb_device *udev, struct
471786baecfSMauro Carvalho Chehab 		dvb_usb_device_properties *props, struct dvb_usb_device_description **desc,
472786baecfSMauro Carvalho Chehab 		int *cold)
473786baecfSMauro Carvalho Chehab {
474786baecfSMauro Carvalho Chehab 	*cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0;
475786baecfSMauro Carvalho Chehab 	return 0;
476786baecfSMauro Carvalho Chehab }
477786baecfSMauro Carvalho Chehab 
478786baecfSMauro Carvalho Chehab static int ttusb2_power_ctrl(struct dvb_usb_device *d, int onoff)
479786baecfSMauro Carvalho Chehab {
480786baecfSMauro Carvalho Chehab 	u8 b = onoff;
481786baecfSMauro Carvalho Chehab 	ttusb2_msg(d, CMD_POWER, &b, 0, NULL, 0);
482786baecfSMauro Carvalho Chehab 	return ttusb2_msg(d, CMD_POWER, &b, 1, NULL, 0);
483786baecfSMauro Carvalho Chehab }
484786baecfSMauro Carvalho Chehab 
485786baecfSMauro Carvalho Chehab 
486786baecfSMauro Carvalho Chehab static struct tda10086_config tda10086_config = {
487786baecfSMauro Carvalho Chehab 	.demod_address = 0x0e,
488786baecfSMauro Carvalho Chehab 	.invert = 0,
489786baecfSMauro Carvalho Chehab 	.diseqc_tone = 1,
490786baecfSMauro Carvalho Chehab 	.xtal_freq = TDA10086_XTAL_16M,
491786baecfSMauro Carvalho Chehab };
492786baecfSMauro Carvalho Chehab 
493786baecfSMauro Carvalho Chehab static struct tda10023_config tda10023_config = {
494786baecfSMauro Carvalho Chehab 	.demod_address = 0x0c,
495786baecfSMauro Carvalho Chehab 	.invert = 0,
496786baecfSMauro Carvalho Chehab 	.xtal = 16000000,
497786baecfSMauro Carvalho Chehab 	.pll_m = 11,
498786baecfSMauro Carvalho Chehab 	.pll_p = 3,
499786baecfSMauro Carvalho Chehab 	.pll_n = 1,
500786baecfSMauro Carvalho Chehab 	.deltaf = 0xa511,
501786baecfSMauro Carvalho Chehab };
502786baecfSMauro Carvalho Chehab 
503786baecfSMauro Carvalho Chehab static struct tda10048_config tda10048_config = {
504786baecfSMauro Carvalho Chehab 	.demod_address    = 0x10 >> 1,
505786baecfSMauro Carvalho Chehab 	.output_mode      = TDA10048_PARALLEL_OUTPUT,
506786baecfSMauro Carvalho Chehab 	.inversion        = TDA10048_INVERSION_ON,
507786baecfSMauro Carvalho Chehab 	.dtv6_if_freq_khz = TDA10048_IF_4000,
508786baecfSMauro Carvalho Chehab 	.dtv7_if_freq_khz = TDA10048_IF_4500,
509786baecfSMauro Carvalho Chehab 	.dtv8_if_freq_khz = TDA10048_IF_5000,
510786baecfSMauro Carvalho Chehab 	.clk_freq_khz     = TDA10048_CLK_16000,
511786baecfSMauro Carvalho Chehab 	.no_firmware      = 1,
512786baecfSMauro Carvalho Chehab 	.set_pll          = true ,
513786baecfSMauro Carvalho Chehab 	.pll_m            = 5,
514786baecfSMauro Carvalho Chehab 	.pll_n            = 3,
515786baecfSMauro Carvalho Chehab 	.pll_p            = 0,
516786baecfSMauro Carvalho Chehab };
517786baecfSMauro Carvalho Chehab 
518786baecfSMauro Carvalho Chehab static struct tda827x_config tda827x_config = {
519786baecfSMauro Carvalho Chehab 	.config = 0,
520786baecfSMauro Carvalho Chehab };
521786baecfSMauro Carvalho Chehab 
522786baecfSMauro Carvalho Chehab static int ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap)
523786baecfSMauro Carvalho Chehab {
524786baecfSMauro Carvalho Chehab 	if (usb_set_interface(adap->dev->udev,0,3) < 0)
525786baecfSMauro Carvalho Chehab 		err("set interface to alts=3 failed");
526786baecfSMauro Carvalho Chehab 
527786baecfSMauro Carvalho Chehab 	if ((adap->fe_adap[0].fe = dvb_attach(tda10086_attach, &tda10086_config, &adap->dev->i2c_adap)) == NULL) {
528786baecfSMauro Carvalho Chehab 		deb_info("TDA10086 attach failed\n");
529786baecfSMauro Carvalho Chehab 		return -ENODEV;
530786baecfSMauro Carvalho Chehab 	}
531786baecfSMauro Carvalho Chehab 
532786baecfSMauro Carvalho Chehab 	return 0;
533786baecfSMauro Carvalho Chehab }
534786baecfSMauro Carvalho Chehab 
535786baecfSMauro Carvalho Chehab static int ttusb2_ct3650_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
536786baecfSMauro Carvalho Chehab {
537786baecfSMauro Carvalho Chehab 	struct dvb_usb_adapter *adap = fe->dvb->priv;
538786baecfSMauro Carvalho Chehab 
539786baecfSMauro Carvalho Chehab 	return adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, enable);
540786baecfSMauro Carvalho Chehab }
541786baecfSMauro Carvalho Chehab 
542786baecfSMauro Carvalho Chehab static int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap)
543786baecfSMauro Carvalho Chehab {
544786baecfSMauro Carvalho Chehab 	if (usb_set_interface(adap->dev->udev, 0, 3) < 0)
545786baecfSMauro Carvalho Chehab 		err("set interface to alts=3 failed");
546786baecfSMauro Carvalho Chehab 
547786baecfSMauro Carvalho Chehab 	if (adap->fe_adap[0].fe == NULL) {
548786baecfSMauro Carvalho Chehab 		/* FE 0 DVB-C */
549786baecfSMauro Carvalho Chehab 		adap->fe_adap[0].fe = dvb_attach(tda10023_attach,
550786baecfSMauro Carvalho Chehab 			&tda10023_config, &adap->dev->i2c_adap, 0x48);
551786baecfSMauro Carvalho Chehab 
552786baecfSMauro Carvalho Chehab 		if (adap->fe_adap[0].fe == NULL) {
553786baecfSMauro Carvalho Chehab 			deb_info("TDA10023 attach failed\n");
554786baecfSMauro Carvalho Chehab 			return -ENODEV;
555786baecfSMauro Carvalho Chehab 		}
556786baecfSMauro Carvalho Chehab 		tt3650_ci_init(adap);
557786baecfSMauro Carvalho Chehab 	} else {
558786baecfSMauro Carvalho Chehab 		adap->fe_adap[1].fe = dvb_attach(tda10048_attach,
559786baecfSMauro Carvalho Chehab 			&tda10048_config, &adap->dev->i2c_adap);
560786baecfSMauro Carvalho Chehab 
561786baecfSMauro Carvalho Chehab 		if (adap->fe_adap[1].fe == NULL) {
562786baecfSMauro Carvalho Chehab 			deb_info("TDA10048 attach failed\n");
563786baecfSMauro Carvalho Chehab 			return -ENODEV;
564786baecfSMauro Carvalho Chehab 		}
565786baecfSMauro Carvalho Chehab 
566786baecfSMauro Carvalho Chehab 		/* tuner is behind TDA10023 I2C-gate */
567786baecfSMauro Carvalho Chehab 		adap->fe_adap[1].fe->ops.i2c_gate_ctrl = ttusb2_ct3650_i2c_gate_ctrl;
568786baecfSMauro Carvalho Chehab 
569786baecfSMauro Carvalho Chehab 	}
570786baecfSMauro Carvalho Chehab 
571786baecfSMauro Carvalho Chehab 	return 0;
572786baecfSMauro Carvalho Chehab }
573786baecfSMauro Carvalho Chehab 
574786baecfSMauro Carvalho Chehab static int ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter *adap)
575786baecfSMauro Carvalho Chehab {
576786baecfSMauro Carvalho Chehab 	struct dvb_frontend *fe;
577786baecfSMauro Carvalho Chehab 
578786baecfSMauro Carvalho Chehab 	/* MFE: select correct FE to attach tuner since that's called twice */
579786baecfSMauro Carvalho Chehab 	if (adap->fe_adap[1].fe == NULL)
580786baecfSMauro Carvalho Chehab 		fe = adap->fe_adap[0].fe;
581786baecfSMauro Carvalho Chehab 	else
582786baecfSMauro Carvalho Chehab 		fe = adap->fe_adap[1].fe;
583786baecfSMauro Carvalho Chehab 
584786baecfSMauro Carvalho Chehab 	/* attach tuner */
585786baecfSMauro Carvalho Chehab 	if (dvb_attach(tda827x_attach, fe, 0x61, &adap->dev->i2c_adap, &tda827x_config) == NULL) {
586786baecfSMauro Carvalho Chehab 		printk(KERN_ERR "%s: No tda827x found!\n", __func__);
587786baecfSMauro Carvalho Chehab 		return -ENODEV;
588786baecfSMauro Carvalho Chehab 	}
589786baecfSMauro Carvalho Chehab 	return 0;
590786baecfSMauro Carvalho Chehab }
591786baecfSMauro Carvalho Chehab 
592786baecfSMauro Carvalho Chehab static int ttusb2_tuner_tda826x_attach(struct dvb_usb_adapter *adap)
593786baecfSMauro Carvalho Chehab {
594786baecfSMauro Carvalho Chehab 	if (dvb_attach(tda826x_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap, 0) == NULL) {
595786baecfSMauro Carvalho Chehab 		deb_info("TDA8263 attach failed\n");
596786baecfSMauro Carvalho Chehab 		return -ENODEV;
597786baecfSMauro Carvalho Chehab 	}
598786baecfSMauro Carvalho Chehab 
599786baecfSMauro Carvalho Chehab 	if (dvb_attach(lnbp21_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, 0, 0) == NULL) {
600786baecfSMauro Carvalho Chehab 		deb_info("LNBP21 attach failed\n");
601786baecfSMauro Carvalho Chehab 		return -ENODEV;
602786baecfSMauro Carvalho Chehab 	}
603786baecfSMauro Carvalho Chehab 	return 0;
604786baecfSMauro Carvalho Chehab }
605786baecfSMauro Carvalho Chehab 
606786baecfSMauro Carvalho Chehab /* DVB USB Driver stuff */
607786baecfSMauro Carvalho Chehab static struct dvb_usb_device_properties ttusb2_properties;
608786baecfSMauro Carvalho Chehab static struct dvb_usb_device_properties ttusb2_properties_s2400;
609786baecfSMauro Carvalho Chehab static struct dvb_usb_device_properties ttusb2_properties_ct3650;
610786baecfSMauro Carvalho Chehab 
611786baecfSMauro Carvalho Chehab static void ttusb2_usb_disconnect(struct usb_interface *intf)
612786baecfSMauro Carvalho Chehab {
613786baecfSMauro Carvalho Chehab 	struct dvb_usb_device *d = usb_get_intfdata(intf);
614786baecfSMauro Carvalho Chehab 
615786baecfSMauro Carvalho Chehab 	tt3650_ci_uninit(d);
616786baecfSMauro Carvalho Chehab 	dvb_usb_device_exit(intf);
617786baecfSMauro Carvalho Chehab }
618786baecfSMauro Carvalho Chehab 
619786baecfSMauro Carvalho Chehab static int ttusb2_probe(struct usb_interface *intf,
620786baecfSMauro Carvalho Chehab 		const struct usb_device_id *id)
621786baecfSMauro Carvalho Chehab {
622786baecfSMauro Carvalho Chehab 	if (0 == dvb_usb_device_init(intf, &ttusb2_properties,
623786baecfSMauro Carvalho Chehab 				     THIS_MODULE, NULL, adapter_nr) ||
624786baecfSMauro Carvalho Chehab 	    0 == dvb_usb_device_init(intf, &ttusb2_properties_s2400,
625786baecfSMauro Carvalho Chehab 				     THIS_MODULE, NULL, adapter_nr) ||
626786baecfSMauro Carvalho Chehab 	    0 == dvb_usb_device_init(intf, &ttusb2_properties_ct3650,
627786baecfSMauro Carvalho Chehab 				     THIS_MODULE, NULL, adapter_nr))
628786baecfSMauro Carvalho Chehab 		return 0;
629786baecfSMauro Carvalho Chehab 	return -ENODEV;
630786baecfSMauro Carvalho Chehab }
631786baecfSMauro Carvalho Chehab 
632786baecfSMauro Carvalho Chehab static struct usb_device_id ttusb2_table [] = {
633786baecfSMauro Carvalho Chehab 	{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_400E) },
634786baecfSMauro Carvalho Chehab 	{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_450E) },
635786baecfSMauro Carvalho Chehab 	{ USB_DEVICE(USB_VID_TECHNOTREND,
636786baecfSMauro Carvalho Chehab 		USB_PID_TECHNOTREND_CONNECT_S2400) },
637786baecfSMauro Carvalho Chehab 	{ USB_DEVICE(USB_VID_TECHNOTREND,
638786baecfSMauro Carvalho Chehab 		USB_PID_TECHNOTREND_CONNECT_CT3650) },
639ed72d37aSChristoph Nuscheler 	{ USB_DEVICE(USB_VID_TECHNOTREND,
640ed72d37aSChristoph Nuscheler 		USB_PID_TECHNOTREND_CONNECT_S2400_8KEEPROM) },
641786baecfSMauro Carvalho Chehab 	{}		/* Terminating entry */
642786baecfSMauro Carvalho Chehab };
643786baecfSMauro Carvalho Chehab MODULE_DEVICE_TABLE (usb, ttusb2_table);
644786baecfSMauro Carvalho Chehab 
645786baecfSMauro Carvalho Chehab static struct dvb_usb_device_properties ttusb2_properties = {
646786baecfSMauro Carvalho Chehab 	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
647786baecfSMauro Carvalho Chehab 
648786baecfSMauro Carvalho Chehab 	.usb_ctrl = CYPRESS_FX2,
649786baecfSMauro Carvalho Chehab 	.firmware = "dvb-usb-pctv-400e-01.fw",
650786baecfSMauro Carvalho Chehab 
651786baecfSMauro Carvalho Chehab 	.size_of_priv = sizeof(struct ttusb2_state),
652786baecfSMauro Carvalho Chehab 
653786baecfSMauro Carvalho Chehab 	.num_adapters = 1,
654786baecfSMauro Carvalho Chehab 	.adapter = {
655786baecfSMauro Carvalho Chehab 		{
656786baecfSMauro Carvalho Chehab 		.num_frontends = 1,
657786baecfSMauro Carvalho Chehab 		.fe = {{
658786baecfSMauro Carvalho Chehab 			.streaming_ctrl   = NULL, // ttusb2_streaming_ctrl,
659786baecfSMauro Carvalho Chehab 
660786baecfSMauro Carvalho Chehab 			.frontend_attach  = ttusb2_frontend_tda10086_attach,
661786baecfSMauro Carvalho Chehab 			.tuner_attach     = ttusb2_tuner_tda826x_attach,
662786baecfSMauro Carvalho Chehab 
663786baecfSMauro Carvalho Chehab 			/* parameter for the MPEG2-data transfer */
664786baecfSMauro Carvalho Chehab 			.stream = {
665786baecfSMauro Carvalho Chehab 				.type = USB_ISOC,
666786baecfSMauro Carvalho Chehab 				.count = 5,
667786baecfSMauro Carvalho Chehab 				.endpoint = 0x02,
668786baecfSMauro Carvalho Chehab 				.u = {
669786baecfSMauro Carvalho Chehab 					.isoc = {
670786baecfSMauro Carvalho Chehab 						.framesperurb = 4,
671786baecfSMauro Carvalho Chehab 						.framesize = 940,
672786baecfSMauro Carvalho Chehab 						.interval = 1,
673786baecfSMauro Carvalho Chehab 					}
674786baecfSMauro Carvalho Chehab 				}
675786baecfSMauro Carvalho Chehab 			}
676786baecfSMauro Carvalho Chehab 		}},
677786baecfSMauro Carvalho Chehab 		}
678786baecfSMauro Carvalho Chehab 	},
679786baecfSMauro Carvalho Chehab 
680786baecfSMauro Carvalho Chehab 	.power_ctrl       = ttusb2_power_ctrl,
681786baecfSMauro Carvalho Chehab 	.identify_state   = ttusb2_identify_state,
682786baecfSMauro Carvalho Chehab 
683786baecfSMauro Carvalho Chehab 	.i2c_algo         = &ttusb2_i2c_algo,
684786baecfSMauro Carvalho Chehab 
685786baecfSMauro Carvalho Chehab 	.generic_bulk_ctrl_endpoint = 0x01,
686786baecfSMauro Carvalho Chehab 
687786baecfSMauro Carvalho Chehab 	.num_device_descs = 2,
688786baecfSMauro Carvalho Chehab 	.devices = {
689786baecfSMauro Carvalho Chehab 		{   "Pinnacle 400e DVB-S USB2.0",
690786baecfSMauro Carvalho Chehab 			{ &ttusb2_table[0], NULL },
691786baecfSMauro Carvalho Chehab 			{ NULL },
692786baecfSMauro Carvalho Chehab 		},
693786baecfSMauro Carvalho Chehab 		{   "Pinnacle 450e DVB-S USB2.0",
694786baecfSMauro Carvalho Chehab 			{ &ttusb2_table[1], NULL },
695786baecfSMauro Carvalho Chehab 			{ NULL },
696786baecfSMauro Carvalho Chehab 		},
697786baecfSMauro Carvalho Chehab 	}
698786baecfSMauro Carvalho Chehab };
699786baecfSMauro Carvalho Chehab 
700786baecfSMauro Carvalho Chehab static struct dvb_usb_device_properties ttusb2_properties_s2400 = {
701786baecfSMauro Carvalho Chehab 	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
702786baecfSMauro Carvalho Chehab 
703786baecfSMauro Carvalho Chehab 	.usb_ctrl = CYPRESS_FX2,
704786baecfSMauro Carvalho Chehab 	.firmware = "dvb-usb-tt-s2400-01.fw",
705786baecfSMauro Carvalho Chehab 
706786baecfSMauro Carvalho Chehab 	.size_of_priv = sizeof(struct ttusb2_state),
707786baecfSMauro Carvalho Chehab 
708786baecfSMauro Carvalho Chehab 	.num_adapters = 1,
709786baecfSMauro Carvalho Chehab 	.adapter = {
710786baecfSMauro Carvalho Chehab 		{
711786baecfSMauro Carvalho Chehab 		.num_frontends = 1,
712786baecfSMauro Carvalho Chehab 		.fe = {{
713786baecfSMauro Carvalho Chehab 			.streaming_ctrl   = NULL,
714786baecfSMauro Carvalho Chehab 
715786baecfSMauro Carvalho Chehab 			.frontend_attach  = ttusb2_frontend_tda10086_attach,
716786baecfSMauro Carvalho Chehab 			.tuner_attach     = ttusb2_tuner_tda826x_attach,
717786baecfSMauro Carvalho Chehab 
718786baecfSMauro Carvalho Chehab 			/* parameter for the MPEG2-data transfer */
719786baecfSMauro Carvalho Chehab 			.stream = {
720786baecfSMauro Carvalho Chehab 				.type = USB_ISOC,
721786baecfSMauro Carvalho Chehab 				.count = 5,
722786baecfSMauro Carvalho Chehab 				.endpoint = 0x02,
723786baecfSMauro Carvalho Chehab 				.u = {
724786baecfSMauro Carvalho Chehab 					.isoc = {
725786baecfSMauro Carvalho Chehab 						.framesperurb = 4,
726786baecfSMauro Carvalho Chehab 						.framesize = 940,
727786baecfSMauro Carvalho Chehab 						.interval = 1,
728786baecfSMauro Carvalho Chehab 					}
729786baecfSMauro Carvalho Chehab 				}
730786baecfSMauro Carvalho Chehab 			}
731786baecfSMauro Carvalho Chehab 		}},
732786baecfSMauro Carvalho Chehab 		}
733786baecfSMauro Carvalho Chehab 	},
734786baecfSMauro Carvalho Chehab 
735786baecfSMauro Carvalho Chehab 	.power_ctrl       = ttusb2_power_ctrl,
736786baecfSMauro Carvalho Chehab 	.identify_state   = ttusb2_identify_state,
737786baecfSMauro Carvalho Chehab 
738786baecfSMauro Carvalho Chehab 	.i2c_algo         = &ttusb2_i2c_algo,
739786baecfSMauro Carvalho Chehab 
740786baecfSMauro Carvalho Chehab 	.generic_bulk_ctrl_endpoint = 0x01,
741786baecfSMauro Carvalho Chehab 
742ed72d37aSChristoph Nuscheler 	.num_device_descs = 2,
743786baecfSMauro Carvalho Chehab 	.devices = {
744786baecfSMauro Carvalho Chehab 		{   "Technotrend TT-connect S-2400",
745786baecfSMauro Carvalho Chehab 			{ &ttusb2_table[2], NULL },
746786baecfSMauro Carvalho Chehab 			{ NULL },
747786baecfSMauro Carvalho Chehab 		},
748ed72d37aSChristoph Nuscheler 		{   "Technotrend TT-connect S-2400 (8kB EEPROM)",
749ed72d37aSChristoph Nuscheler 			{ &ttusb2_table[4], NULL },
750ed72d37aSChristoph Nuscheler 			{ NULL },
751ed72d37aSChristoph Nuscheler 		},
752786baecfSMauro Carvalho Chehab 	}
753786baecfSMauro Carvalho Chehab };
754786baecfSMauro Carvalho Chehab 
755786baecfSMauro Carvalho Chehab static struct dvb_usb_device_properties ttusb2_properties_ct3650 = {
756786baecfSMauro Carvalho Chehab 	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
757786baecfSMauro Carvalho Chehab 
758786baecfSMauro Carvalho Chehab 	.usb_ctrl = CYPRESS_FX2,
759786baecfSMauro Carvalho Chehab 
760786baecfSMauro Carvalho Chehab 	.size_of_priv = sizeof(struct ttusb2_state),
761786baecfSMauro Carvalho Chehab 
762786baecfSMauro Carvalho Chehab 	.rc.core = {
763786baecfSMauro Carvalho Chehab 		.rc_interval      = 150, /* Less than IR_KEYPRESS_TIMEOUT */
764786baecfSMauro Carvalho Chehab 		.rc_codes         = RC_MAP_TT_1500,
765786baecfSMauro Carvalho Chehab 		.rc_query         = tt3650_rc_query,
7666d741bfeSSean Young 		.allowed_protos   = RC_PROTO_BIT_RC5,
767786baecfSMauro Carvalho Chehab 	},
768786baecfSMauro Carvalho Chehab 
769786baecfSMauro Carvalho Chehab 	.num_adapters = 1,
770786baecfSMauro Carvalho Chehab 	.adapter = {
771786baecfSMauro Carvalho Chehab 		{
772786baecfSMauro Carvalho Chehab 		.num_frontends = 2,
773786baecfSMauro Carvalho Chehab 		.fe = {{
774786baecfSMauro Carvalho Chehab 			.streaming_ctrl   = NULL,
775786baecfSMauro Carvalho Chehab 
776786baecfSMauro Carvalho Chehab 			.frontend_attach  = ttusb2_frontend_tda10023_attach,
777786baecfSMauro Carvalho Chehab 			.tuner_attach = ttusb2_tuner_tda827x_attach,
778786baecfSMauro Carvalho Chehab 
779786baecfSMauro Carvalho Chehab 			/* parameter for the MPEG2-data transfer */
780786baecfSMauro Carvalho Chehab 			.stream = {
781786baecfSMauro Carvalho Chehab 				.type = USB_ISOC,
782786baecfSMauro Carvalho Chehab 				.count = 5,
783786baecfSMauro Carvalho Chehab 				.endpoint = 0x02,
784786baecfSMauro Carvalho Chehab 				.u = {
785786baecfSMauro Carvalho Chehab 					.isoc = {
786786baecfSMauro Carvalho Chehab 						.framesperurb = 4,
787786baecfSMauro Carvalho Chehab 						.framesize = 940,
788786baecfSMauro Carvalho Chehab 						.interval = 1,
789786baecfSMauro Carvalho Chehab 					}
790786baecfSMauro Carvalho Chehab 				}
791786baecfSMauro Carvalho Chehab 			}
792786baecfSMauro Carvalho Chehab 		}, {
793786baecfSMauro Carvalho Chehab 			.streaming_ctrl   = NULL,
794786baecfSMauro Carvalho Chehab 
795786baecfSMauro Carvalho Chehab 			.frontend_attach  = ttusb2_frontend_tda10023_attach,
796786baecfSMauro Carvalho Chehab 			.tuner_attach = ttusb2_tuner_tda827x_attach,
797786baecfSMauro Carvalho Chehab 
798786baecfSMauro Carvalho Chehab 			/* parameter for the MPEG2-data transfer */
799786baecfSMauro Carvalho Chehab 			.stream = {
800786baecfSMauro Carvalho Chehab 				.type = USB_ISOC,
801786baecfSMauro Carvalho Chehab 				.count = 5,
802786baecfSMauro Carvalho Chehab 				.endpoint = 0x02,
803786baecfSMauro Carvalho Chehab 				.u = {
804786baecfSMauro Carvalho Chehab 					.isoc = {
805786baecfSMauro Carvalho Chehab 						.framesperurb = 4,
806786baecfSMauro Carvalho Chehab 						.framesize = 940,
807786baecfSMauro Carvalho Chehab 						.interval = 1,
808786baecfSMauro Carvalho Chehab 					}
809786baecfSMauro Carvalho Chehab 				}
810786baecfSMauro Carvalho Chehab 			}
811786baecfSMauro Carvalho Chehab 		}},
812786baecfSMauro Carvalho Chehab 		},
813786baecfSMauro Carvalho Chehab 	},
814786baecfSMauro Carvalho Chehab 
815786baecfSMauro Carvalho Chehab 	.power_ctrl       = ttusb2_power_ctrl,
816786baecfSMauro Carvalho Chehab 	.identify_state   = ttusb2_identify_state,
817786baecfSMauro Carvalho Chehab 
818786baecfSMauro Carvalho Chehab 	.i2c_algo         = &ttusb2_i2c_algo,
819786baecfSMauro Carvalho Chehab 
820786baecfSMauro Carvalho Chehab 	.generic_bulk_ctrl_endpoint = 0x01,
821786baecfSMauro Carvalho Chehab 
822786baecfSMauro Carvalho Chehab 	.num_device_descs = 1,
823786baecfSMauro Carvalho Chehab 	.devices = {
824786baecfSMauro Carvalho Chehab 		{   "Technotrend TT-connect CT-3650",
825786baecfSMauro Carvalho Chehab 			.warm_ids = { &ttusb2_table[3], NULL },
826786baecfSMauro Carvalho Chehab 		},
827786baecfSMauro Carvalho Chehab 	}
828786baecfSMauro Carvalho Chehab };
829786baecfSMauro Carvalho Chehab 
830786baecfSMauro Carvalho Chehab static struct usb_driver ttusb2_driver = {
831786baecfSMauro Carvalho Chehab 	.name		= "dvb_usb_ttusb2",
832786baecfSMauro Carvalho Chehab 	.probe		= ttusb2_probe,
833786baecfSMauro Carvalho Chehab 	.disconnect	= ttusb2_usb_disconnect,
834786baecfSMauro Carvalho Chehab 	.id_table	= ttusb2_table,
835786baecfSMauro Carvalho Chehab };
836786baecfSMauro Carvalho Chehab 
837786baecfSMauro Carvalho Chehab module_usb_driver(ttusb2_driver);
838786baecfSMauro Carvalho Chehab 
83999e44da7SPatrick Boettcher MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
840786baecfSMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for Pinnacle PCTV 400e DVB-S USB2.0");
841786baecfSMauro Carvalho Chehab MODULE_VERSION("1.0");
842786baecfSMauro Carvalho Chehab MODULE_LICENSE("GPL");
843