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