xref: /linux/drivers/media/usb/dvb-usb/ttusb2.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
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  *
20577a7ad3SMauro 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 
ttusb2_msg(struct dvb_usb_device * d,u8 cmd,u8 * wbuf,int wlen,u8 * rbuf,int rlen)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 */
tt3650_ci_msg(struct dvb_usb_device * d,u8 cmd,u8 * data,unsigned int write_len,unsigned int read_len)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 
tt3650_ci_msg_locked(struct dvb_ca_en50221 * ca,u8 cmd,u8 * data,unsigned int write_len,unsigned int read_len)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 
tt3650_ci_read_attribute_mem(struct dvb_ca_en50221 * ca,int slot,int address)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 
tt3650_ci_write_attribute_mem(struct dvb_ca_en50221 * ca,int slot,int address,u8 value)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 
tt3650_ci_read_cam_control(struct dvb_ca_en50221 * ca,int slot,u8 address)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 
tt3650_ci_write_cam_control(struct dvb_ca_en50221 * ca,int slot,u8 address,u8 value)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 
tt3650_ci_set_video_port(struct dvb_ca_en50221 * ca,int slot,int enable)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 
tt3650_ci_slot_shutdown(struct dvb_ca_en50221 * ca,int slot)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 
tt3650_ci_slot_ts_enable(struct dvb_ca_en50221 * ca,int slot)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 
tt3650_ci_slot_reset(struct dvb_ca_en50221 * ca,int slot)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 
tt3650_ci_poll_slot_status(struct dvb_ca_en50221 * ca,int slot,int open)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 
tt3650_ci_uninit(struct dvb_usb_device * d)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 
tt3650_ci_init(struct dvb_usb_adapter * a)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 
ttusb2_i2c_xfer(struct i2c_adapter * adap,struct i2c_msg msg[],int num)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 
ttusb2_i2c_func(struct i2c_adapter * adapter)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 */
tt3650_rc_query(struct dvb_usb_device * d)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 */
ttusb2_identify_state(struct usb_device * udev,const struct dvb_usb_device_properties * props,const struct dvb_usb_device_description ** desc,int * cold)470d27958dfSSean Young static int ttusb2_identify_state(struct usb_device *udev,
471d27958dfSSean Young 				 const struct dvb_usb_device_properties *props,
472d27958dfSSean Young 				 const struct dvb_usb_device_description **desc,
473786baecfSMauro Carvalho Chehab 				 int *cold)
474786baecfSMauro Carvalho Chehab {
475786baecfSMauro Carvalho Chehab 	*cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0;
476786baecfSMauro Carvalho Chehab 	return 0;
477786baecfSMauro Carvalho Chehab }
478786baecfSMauro Carvalho Chehab 
ttusb2_power_ctrl(struct dvb_usb_device * d,int onoff)479786baecfSMauro Carvalho Chehab static int ttusb2_power_ctrl(struct dvb_usb_device *d, int onoff)
480786baecfSMauro Carvalho Chehab {
481786baecfSMauro Carvalho Chehab 	u8 b = onoff;
482786baecfSMauro Carvalho Chehab 	ttusb2_msg(d, CMD_POWER, &b, 0, NULL, 0);
483786baecfSMauro Carvalho Chehab 	return ttusb2_msg(d, CMD_POWER, &b, 1, NULL, 0);
484786baecfSMauro Carvalho Chehab }
485786baecfSMauro Carvalho Chehab 
486786baecfSMauro Carvalho Chehab 
487786baecfSMauro Carvalho Chehab static struct tda10086_config tda10086_config = {
488786baecfSMauro Carvalho Chehab 	.demod_address = 0x0e,
489786baecfSMauro Carvalho Chehab 	.invert = 0,
490786baecfSMauro Carvalho Chehab 	.diseqc_tone = 1,
491786baecfSMauro Carvalho Chehab 	.xtal_freq = TDA10086_XTAL_16M,
492786baecfSMauro Carvalho Chehab };
493786baecfSMauro Carvalho Chehab 
494786baecfSMauro Carvalho Chehab static struct tda10023_config tda10023_config = {
495786baecfSMauro Carvalho Chehab 	.demod_address = 0x0c,
496786baecfSMauro Carvalho Chehab 	.invert = 0,
497786baecfSMauro Carvalho Chehab 	.xtal = 16000000,
498786baecfSMauro Carvalho Chehab 	.pll_m = 11,
499786baecfSMauro Carvalho Chehab 	.pll_p = 3,
500786baecfSMauro Carvalho Chehab 	.pll_n = 1,
501786baecfSMauro Carvalho Chehab 	.deltaf = 0xa511,
502786baecfSMauro Carvalho Chehab };
503786baecfSMauro Carvalho Chehab 
504786baecfSMauro Carvalho Chehab static struct tda10048_config tda10048_config = {
505786baecfSMauro Carvalho Chehab 	.demod_address    = 0x10 >> 1,
506786baecfSMauro Carvalho Chehab 	.output_mode      = TDA10048_PARALLEL_OUTPUT,
507786baecfSMauro Carvalho Chehab 	.inversion        = TDA10048_INVERSION_ON,
508786baecfSMauro Carvalho Chehab 	.dtv6_if_freq_khz = TDA10048_IF_4000,
509786baecfSMauro Carvalho Chehab 	.dtv7_if_freq_khz = TDA10048_IF_4500,
510786baecfSMauro Carvalho Chehab 	.dtv8_if_freq_khz = TDA10048_IF_5000,
511786baecfSMauro Carvalho Chehab 	.clk_freq_khz     = TDA10048_CLK_16000,
512786baecfSMauro Carvalho Chehab 	.no_firmware      = 1,
513786baecfSMauro Carvalho Chehab 	.set_pll          = true ,
514786baecfSMauro Carvalho Chehab 	.pll_m            = 5,
515786baecfSMauro Carvalho Chehab 	.pll_n            = 3,
516786baecfSMauro Carvalho Chehab 	.pll_p            = 0,
517786baecfSMauro Carvalho Chehab };
518786baecfSMauro Carvalho Chehab 
519786baecfSMauro Carvalho Chehab static struct tda827x_config tda827x_config = {
520786baecfSMauro Carvalho Chehab 	.config = 0,
521786baecfSMauro Carvalho Chehab };
522786baecfSMauro Carvalho Chehab 
ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter * adap)523786baecfSMauro Carvalho Chehab static int ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap)
524786baecfSMauro Carvalho Chehab {
525786baecfSMauro Carvalho Chehab 	if (usb_set_interface(adap->dev->udev,0,3) < 0)
526786baecfSMauro Carvalho Chehab 		err("set interface to alts=3 failed");
527786baecfSMauro Carvalho Chehab 
528786baecfSMauro Carvalho Chehab 	if ((adap->fe_adap[0].fe = dvb_attach(tda10086_attach, &tda10086_config, &adap->dev->i2c_adap)) == NULL) {
529786baecfSMauro Carvalho Chehab 		deb_info("TDA10086 attach failed\n");
530786baecfSMauro Carvalho Chehab 		return -ENODEV;
531786baecfSMauro Carvalho Chehab 	}
532786baecfSMauro Carvalho Chehab 
533786baecfSMauro Carvalho Chehab 	return 0;
534786baecfSMauro Carvalho Chehab }
535786baecfSMauro Carvalho Chehab 
ttusb2_ct3650_i2c_gate_ctrl(struct dvb_frontend * fe,int enable)536786baecfSMauro Carvalho Chehab static int ttusb2_ct3650_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
537786baecfSMauro Carvalho Chehab {
538786baecfSMauro Carvalho Chehab 	struct dvb_usb_adapter *adap = fe->dvb->priv;
539786baecfSMauro Carvalho Chehab 
540786baecfSMauro Carvalho Chehab 	return adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, enable);
541786baecfSMauro Carvalho Chehab }
542786baecfSMauro Carvalho Chehab 
ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter * adap)543786baecfSMauro Carvalho Chehab static int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap)
544786baecfSMauro Carvalho Chehab {
545786baecfSMauro Carvalho Chehab 	if (usb_set_interface(adap->dev->udev, 0, 3) < 0)
546786baecfSMauro Carvalho Chehab 		err("set interface to alts=3 failed");
547786baecfSMauro Carvalho Chehab 
548786baecfSMauro Carvalho Chehab 	if (adap->fe_adap[0].fe == NULL) {
549786baecfSMauro Carvalho Chehab 		/* FE 0 DVB-C */
550786baecfSMauro Carvalho Chehab 		adap->fe_adap[0].fe = dvb_attach(tda10023_attach,
551786baecfSMauro Carvalho Chehab 			&tda10023_config, &adap->dev->i2c_adap, 0x48);
552786baecfSMauro Carvalho Chehab 
553786baecfSMauro Carvalho Chehab 		if (adap->fe_adap[0].fe == NULL) {
554786baecfSMauro Carvalho Chehab 			deb_info("TDA10023 attach failed\n");
555786baecfSMauro Carvalho Chehab 			return -ENODEV;
556786baecfSMauro Carvalho Chehab 		}
557786baecfSMauro Carvalho Chehab 		tt3650_ci_init(adap);
558786baecfSMauro Carvalho Chehab 	} else {
559786baecfSMauro Carvalho Chehab 		adap->fe_adap[1].fe = dvb_attach(tda10048_attach,
560786baecfSMauro Carvalho Chehab 			&tda10048_config, &adap->dev->i2c_adap);
561786baecfSMauro Carvalho Chehab 
562786baecfSMauro Carvalho Chehab 		if (adap->fe_adap[1].fe == NULL) {
563786baecfSMauro Carvalho Chehab 			deb_info("TDA10048 attach failed\n");
564786baecfSMauro Carvalho Chehab 			return -ENODEV;
565786baecfSMauro Carvalho Chehab 		}
566786baecfSMauro Carvalho Chehab 
567786baecfSMauro Carvalho Chehab 		/* tuner is behind TDA10023 I2C-gate */
568786baecfSMauro Carvalho Chehab 		adap->fe_adap[1].fe->ops.i2c_gate_ctrl = ttusb2_ct3650_i2c_gate_ctrl;
569786baecfSMauro Carvalho Chehab 
570786baecfSMauro Carvalho Chehab 	}
571786baecfSMauro Carvalho Chehab 
572786baecfSMauro Carvalho Chehab 	return 0;
573786baecfSMauro Carvalho Chehab }
574786baecfSMauro Carvalho Chehab 
ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter * adap)575786baecfSMauro Carvalho Chehab static int ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter *adap)
576786baecfSMauro Carvalho Chehab {
577786baecfSMauro Carvalho Chehab 	struct dvb_frontend *fe;
578786baecfSMauro Carvalho Chehab 
579786baecfSMauro Carvalho Chehab 	/* MFE: select correct FE to attach tuner since that's called twice */
580786baecfSMauro Carvalho Chehab 	if (adap->fe_adap[1].fe == NULL)
581786baecfSMauro Carvalho Chehab 		fe = adap->fe_adap[0].fe;
582786baecfSMauro Carvalho Chehab 	else
583786baecfSMauro Carvalho Chehab 		fe = adap->fe_adap[1].fe;
584786baecfSMauro Carvalho Chehab 
585786baecfSMauro Carvalho Chehab 	/* attach tuner */
586786baecfSMauro Carvalho Chehab 	if (dvb_attach(tda827x_attach, fe, 0x61, &adap->dev->i2c_adap, &tda827x_config) == NULL) {
587786baecfSMauro Carvalho Chehab 		printk(KERN_ERR "%s: No tda827x found!\n", __func__);
588786baecfSMauro Carvalho Chehab 		return -ENODEV;
589786baecfSMauro Carvalho Chehab 	}
590786baecfSMauro Carvalho Chehab 	return 0;
591786baecfSMauro Carvalho Chehab }
592786baecfSMauro Carvalho Chehab 
ttusb2_tuner_tda826x_attach(struct dvb_usb_adapter * adap)593786baecfSMauro Carvalho Chehab static int ttusb2_tuner_tda826x_attach(struct dvb_usb_adapter *adap)
594786baecfSMauro Carvalho Chehab {
595786baecfSMauro Carvalho Chehab 	if (dvb_attach(tda826x_attach, adap->fe_adap[0].fe, 0x60, &adap->dev->i2c_adap, 0) == NULL) {
596786baecfSMauro Carvalho Chehab 		deb_info("TDA8263 attach failed\n");
597786baecfSMauro Carvalho Chehab 		return -ENODEV;
598786baecfSMauro Carvalho Chehab 	}
599786baecfSMauro Carvalho Chehab 
600786baecfSMauro Carvalho Chehab 	if (dvb_attach(lnbp21_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, 0, 0) == NULL) {
601786baecfSMauro Carvalho Chehab 		deb_info("LNBP21 attach failed\n");
602786baecfSMauro Carvalho Chehab 		return -ENODEV;
603786baecfSMauro Carvalho Chehab 	}
604786baecfSMauro Carvalho Chehab 	return 0;
605786baecfSMauro Carvalho Chehab }
606786baecfSMauro Carvalho Chehab 
607786baecfSMauro Carvalho Chehab /* DVB USB Driver stuff */
608786baecfSMauro Carvalho Chehab static struct dvb_usb_device_properties ttusb2_properties;
609786baecfSMauro Carvalho Chehab static struct dvb_usb_device_properties ttusb2_properties_s2400;
610786baecfSMauro Carvalho Chehab static struct dvb_usb_device_properties ttusb2_properties_ct3650;
611786baecfSMauro Carvalho Chehab 
ttusb2_usb_disconnect(struct usb_interface * intf)612786baecfSMauro Carvalho Chehab static void ttusb2_usb_disconnect(struct usb_interface *intf)
613786baecfSMauro Carvalho Chehab {
614786baecfSMauro Carvalho Chehab 	struct dvb_usb_device *d = usb_get_intfdata(intf);
615786baecfSMauro Carvalho Chehab 
616786baecfSMauro Carvalho Chehab 	tt3650_ci_uninit(d);
617786baecfSMauro Carvalho Chehab 	dvb_usb_device_exit(intf);
618786baecfSMauro Carvalho Chehab }
619786baecfSMauro Carvalho Chehab 
ttusb2_probe(struct usb_interface * intf,const struct usb_device_id * id)620786baecfSMauro Carvalho Chehab static int ttusb2_probe(struct usb_interface *intf,
621786baecfSMauro Carvalho Chehab 		const struct usb_device_id *id)
622786baecfSMauro Carvalho Chehab {
623786baecfSMauro Carvalho Chehab 	if (0 == dvb_usb_device_init(intf, &ttusb2_properties,
624786baecfSMauro Carvalho Chehab 				     THIS_MODULE, NULL, adapter_nr) ||
625786baecfSMauro Carvalho Chehab 	    0 == dvb_usb_device_init(intf, &ttusb2_properties_s2400,
626786baecfSMauro Carvalho Chehab 				     THIS_MODULE, NULL, adapter_nr) ||
627786baecfSMauro Carvalho Chehab 	    0 == dvb_usb_device_init(intf, &ttusb2_properties_ct3650,
628786baecfSMauro Carvalho Chehab 				     THIS_MODULE, NULL, adapter_nr))
629786baecfSMauro Carvalho Chehab 		return 0;
630786baecfSMauro Carvalho Chehab 	return -ENODEV;
631786baecfSMauro Carvalho Chehab }
632786baecfSMauro Carvalho Chehab 
633*5c1a56c9SMauro Carvalho Chehab enum {
634*5c1a56c9SMauro Carvalho Chehab 	PINNACLE_PCTV_400E,
635*5c1a56c9SMauro Carvalho Chehab 	PINNACLE_PCTV_450E,
636*5c1a56c9SMauro Carvalho Chehab 	TECHNOTREND_CONNECT_S2400,
637*5c1a56c9SMauro Carvalho Chehab 	TECHNOTREND_CONNECT_CT3650,
638*5c1a56c9SMauro Carvalho Chehab 	TECHNOTREND_CONNECT_S2400_8KEEPROM,
639786baecfSMauro Carvalho Chehab };
640*5c1a56c9SMauro Carvalho Chehab 
641*5c1a56c9SMauro Carvalho Chehab static struct usb_device_id ttusb2_table[] = {
642*5c1a56c9SMauro Carvalho Chehab 	DVB_USB_DEV(PINNACLE, PINNACLE_PCTV_400E),
643*5c1a56c9SMauro Carvalho Chehab 	DVB_USB_DEV(PINNACLE, PINNACLE_PCTV_450E),
644*5c1a56c9SMauro Carvalho Chehab 	DVB_USB_DEV(TECHNOTREND, TECHNOTREND_CONNECT_S2400),
645*5c1a56c9SMauro Carvalho Chehab 	DVB_USB_DEV(TECHNOTREND, TECHNOTREND_CONNECT_CT3650),
646*5c1a56c9SMauro Carvalho Chehab 	DVB_USB_DEV(TECHNOTREND, TECHNOTREND_CONNECT_S2400_8KEEPROM),
647*5c1a56c9SMauro Carvalho Chehab 	{ }
648*5c1a56c9SMauro Carvalho Chehab };
649*5c1a56c9SMauro Carvalho Chehab 
650786baecfSMauro Carvalho Chehab MODULE_DEVICE_TABLE (usb, ttusb2_table);
651786baecfSMauro Carvalho Chehab 
652786baecfSMauro Carvalho Chehab static struct dvb_usb_device_properties ttusb2_properties = {
653786baecfSMauro Carvalho Chehab 	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
654786baecfSMauro Carvalho Chehab 
655786baecfSMauro Carvalho Chehab 	.usb_ctrl = CYPRESS_FX2,
656786baecfSMauro Carvalho Chehab 	.firmware = "dvb-usb-pctv-400e-01.fw",
657786baecfSMauro Carvalho Chehab 
658786baecfSMauro Carvalho Chehab 	.size_of_priv = sizeof(struct ttusb2_state),
659786baecfSMauro Carvalho Chehab 
660786baecfSMauro Carvalho Chehab 	.num_adapters = 1,
661786baecfSMauro Carvalho Chehab 	.adapter = {
662786baecfSMauro Carvalho Chehab 		{
663786baecfSMauro Carvalho Chehab 		.num_frontends = 1,
664786baecfSMauro Carvalho Chehab 		.fe = {{
665786baecfSMauro Carvalho Chehab 			.streaming_ctrl   = NULL, // ttusb2_streaming_ctrl,
666786baecfSMauro Carvalho Chehab 
667786baecfSMauro Carvalho Chehab 			.frontend_attach  = ttusb2_frontend_tda10086_attach,
668786baecfSMauro Carvalho Chehab 			.tuner_attach     = ttusb2_tuner_tda826x_attach,
669786baecfSMauro Carvalho Chehab 
670786baecfSMauro Carvalho Chehab 			/* parameter for the MPEG2-data transfer */
671786baecfSMauro Carvalho Chehab 			.stream = {
672786baecfSMauro Carvalho Chehab 				.type = USB_ISOC,
673786baecfSMauro Carvalho Chehab 				.count = 5,
674786baecfSMauro Carvalho Chehab 				.endpoint = 0x02,
675786baecfSMauro Carvalho Chehab 				.u = {
676786baecfSMauro Carvalho Chehab 					.isoc = {
677786baecfSMauro Carvalho Chehab 						.framesperurb = 4,
678786baecfSMauro Carvalho Chehab 						.framesize = 940,
679786baecfSMauro Carvalho Chehab 						.interval = 1,
680786baecfSMauro Carvalho Chehab 					}
681786baecfSMauro Carvalho Chehab 				}
682786baecfSMauro Carvalho Chehab 			}
683786baecfSMauro Carvalho Chehab 		}},
684786baecfSMauro Carvalho Chehab 		}
685786baecfSMauro Carvalho Chehab 	},
686786baecfSMauro Carvalho Chehab 
687786baecfSMauro Carvalho Chehab 	.power_ctrl       = ttusb2_power_ctrl,
688786baecfSMauro Carvalho Chehab 	.identify_state   = ttusb2_identify_state,
689786baecfSMauro Carvalho Chehab 
690786baecfSMauro Carvalho Chehab 	.i2c_algo         = &ttusb2_i2c_algo,
691786baecfSMauro Carvalho Chehab 
692786baecfSMauro Carvalho Chehab 	.generic_bulk_ctrl_endpoint = 0x01,
693786baecfSMauro Carvalho Chehab 
694786baecfSMauro Carvalho Chehab 	.num_device_descs = 2,
695786baecfSMauro Carvalho Chehab 	.devices = {
696786baecfSMauro Carvalho Chehab 		{   "Pinnacle 400e DVB-S USB2.0",
697*5c1a56c9SMauro Carvalho Chehab 			{ &ttusb2_table[PINNACLE_PCTV_400E], NULL },
698786baecfSMauro Carvalho Chehab 			{ NULL },
699786baecfSMauro Carvalho Chehab 		},
700786baecfSMauro Carvalho Chehab 		{   "Pinnacle 450e DVB-S USB2.0",
701*5c1a56c9SMauro Carvalho Chehab 			{ &ttusb2_table[PINNACLE_PCTV_450E], NULL },
702786baecfSMauro Carvalho Chehab 			{ NULL },
703786baecfSMauro Carvalho Chehab 		},
704786baecfSMauro Carvalho Chehab 	}
705786baecfSMauro Carvalho Chehab };
706786baecfSMauro Carvalho Chehab 
707786baecfSMauro Carvalho Chehab static struct dvb_usb_device_properties ttusb2_properties_s2400 = {
708786baecfSMauro Carvalho Chehab 	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
709786baecfSMauro Carvalho Chehab 
710786baecfSMauro Carvalho Chehab 	.usb_ctrl = CYPRESS_FX2,
711786baecfSMauro Carvalho Chehab 	.firmware = "dvb-usb-tt-s2400-01.fw",
712786baecfSMauro Carvalho Chehab 
713786baecfSMauro Carvalho Chehab 	.size_of_priv = sizeof(struct ttusb2_state),
714786baecfSMauro Carvalho Chehab 
715786baecfSMauro Carvalho Chehab 	.num_adapters = 1,
716786baecfSMauro Carvalho Chehab 	.adapter = {
717786baecfSMauro Carvalho Chehab 		{
718786baecfSMauro Carvalho Chehab 		.num_frontends = 1,
719786baecfSMauro Carvalho Chehab 		.fe = {{
720786baecfSMauro Carvalho Chehab 			.streaming_ctrl   = NULL,
721786baecfSMauro Carvalho Chehab 
722786baecfSMauro Carvalho Chehab 			.frontend_attach  = ttusb2_frontend_tda10086_attach,
723786baecfSMauro Carvalho Chehab 			.tuner_attach     = ttusb2_tuner_tda826x_attach,
724786baecfSMauro Carvalho Chehab 
725786baecfSMauro Carvalho Chehab 			/* parameter for the MPEG2-data transfer */
726786baecfSMauro Carvalho Chehab 			.stream = {
727786baecfSMauro Carvalho Chehab 				.type = USB_ISOC,
728786baecfSMauro Carvalho Chehab 				.count = 5,
729786baecfSMauro Carvalho Chehab 				.endpoint = 0x02,
730786baecfSMauro Carvalho Chehab 				.u = {
731786baecfSMauro Carvalho Chehab 					.isoc = {
732786baecfSMauro Carvalho Chehab 						.framesperurb = 4,
733786baecfSMauro Carvalho Chehab 						.framesize = 940,
734786baecfSMauro Carvalho Chehab 						.interval = 1,
735786baecfSMauro Carvalho Chehab 					}
736786baecfSMauro Carvalho Chehab 				}
737786baecfSMauro Carvalho Chehab 			}
738786baecfSMauro Carvalho Chehab 		}},
739786baecfSMauro Carvalho Chehab 		}
740786baecfSMauro Carvalho Chehab 	},
741786baecfSMauro Carvalho Chehab 
742786baecfSMauro Carvalho Chehab 	.power_ctrl       = ttusb2_power_ctrl,
743786baecfSMauro Carvalho Chehab 	.identify_state   = ttusb2_identify_state,
744786baecfSMauro Carvalho Chehab 
745786baecfSMauro Carvalho Chehab 	.i2c_algo         = &ttusb2_i2c_algo,
746786baecfSMauro Carvalho Chehab 
747786baecfSMauro Carvalho Chehab 	.generic_bulk_ctrl_endpoint = 0x01,
748786baecfSMauro Carvalho Chehab 
749ed72d37aSChristoph Nuscheler 	.num_device_descs = 2,
750786baecfSMauro Carvalho Chehab 	.devices = {
751786baecfSMauro Carvalho Chehab 		{   "Technotrend TT-connect S-2400",
752*5c1a56c9SMauro Carvalho Chehab 			{ &ttusb2_table[TECHNOTREND_CONNECT_S2400], NULL },
753786baecfSMauro Carvalho Chehab 			{ NULL },
754786baecfSMauro Carvalho Chehab 		},
755ed72d37aSChristoph Nuscheler 		{   "Technotrend TT-connect S-2400 (8kB EEPROM)",
756*5c1a56c9SMauro Carvalho Chehab 			{ &ttusb2_table[TECHNOTREND_CONNECT_S2400_8KEEPROM], NULL },
757ed72d37aSChristoph Nuscheler 			{ NULL },
758ed72d37aSChristoph Nuscheler 		},
759786baecfSMauro Carvalho Chehab 	}
760786baecfSMauro Carvalho Chehab };
761786baecfSMauro Carvalho Chehab 
762786baecfSMauro Carvalho Chehab static struct dvb_usb_device_properties ttusb2_properties_ct3650 = {
763786baecfSMauro Carvalho Chehab 	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
764786baecfSMauro Carvalho Chehab 
765786baecfSMauro Carvalho Chehab 	.usb_ctrl = CYPRESS_FX2,
766786baecfSMauro Carvalho Chehab 
767786baecfSMauro Carvalho Chehab 	.size_of_priv = sizeof(struct ttusb2_state),
768786baecfSMauro Carvalho Chehab 
769786baecfSMauro Carvalho Chehab 	.rc.core = {
770786baecfSMauro Carvalho Chehab 		.rc_interval      = 150, /* Less than IR_KEYPRESS_TIMEOUT */
771786baecfSMauro Carvalho Chehab 		.rc_codes         = RC_MAP_TT_1500,
772786baecfSMauro Carvalho Chehab 		.rc_query         = tt3650_rc_query,
7736d741bfeSSean Young 		.allowed_protos   = RC_PROTO_BIT_RC5,
774786baecfSMauro Carvalho Chehab 	},
775786baecfSMauro Carvalho Chehab 
776786baecfSMauro Carvalho Chehab 	.num_adapters = 1,
777786baecfSMauro Carvalho Chehab 	.adapter = {
778786baecfSMauro Carvalho Chehab 		{
779786baecfSMauro Carvalho Chehab 		.num_frontends = 2,
780786baecfSMauro Carvalho Chehab 		.fe = {{
781786baecfSMauro Carvalho Chehab 			.streaming_ctrl   = NULL,
782786baecfSMauro Carvalho Chehab 
783786baecfSMauro Carvalho Chehab 			.frontend_attach  = ttusb2_frontend_tda10023_attach,
784786baecfSMauro Carvalho Chehab 			.tuner_attach = ttusb2_tuner_tda827x_attach,
785786baecfSMauro Carvalho Chehab 
786786baecfSMauro Carvalho Chehab 			/* parameter for the MPEG2-data transfer */
787786baecfSMauro Carvalho Chehab 			.stream = {
788786baecfSMauro Carvalho Chehab 				.type = USB_ISOC,
789786baecfSMauro Carvalho Chehab 				.count = 5,
790786baecfSMauro Carvalho Chehab 				.endpoint = 0x02,
791786baecfSMauro Carvalho Chehab 				.u = {
792786baecfSMauro Carvalho Chehab 					.isoc = {
793786baecfSMauro Carvalho Chehab 						.framesperurb = 4,
794786baecfSMauro Carvalho Chehab 						.framesize = 940,
795786baecfSMauro Carvalho Chehab 						.interval = 1,
796786baecfSMauro Carvalho Chehab 					}
797786baecfSMauro Carvalho Chehab 				}
798786baecfSMauro Carvalho Chehab 			}
799786baecfSMauro Carvalho Chehab 		}, {
800786baecfSMauro Carvalho Chehab 			.streaming_ctrl   = NULL,
801786baecfSMauro Carvalho Chehab 
802786baecfSMauro Carvalho Chehab 			.frontend_attach  = ttusb2_frontend_tda10023_attach,
803786baecfSMauro Carvalho Chehab 			.tuner_attach = ttusb2_tuner_tda827x_attach,
804786baecfSMauro Carvalho Chehab 
805786baecfSMauro Carvalho Chehab 			/* parameter for the MPEG2-data transfer */
806786baecfSMauro Carvalho Chehab 			.stream = {
807786baecfSMauro Carvalho Chehab 				.type = USB_ISOC,
808786baecfSMauro Carvalho Chehab 				.count = 5,
809786baecfSMauro Carvalho Chehab 				.endpoint = 0x02,
810786baecfSMauro Carvalho Chehab 				.u = {
811786baecfSMauro Carvalho Chehab 					.isoc = {
812786baecfSMauro Carvalho Chehab 						.framesperurb = 4,
813786baecfSMauro Carvalho Chehab 						.framesize = 940,
814786baecfSMauro Carvalho Chehab 						.interval = 1,
815786baecfSMauro Carvalho Chehab 					}
816786baecfSMauro Carvalho Chehab 				}
817786baecfSMauro Carvalho Chehab 			}
818786baecfSMauro Carvalho Chehab 		}},
819786baecfSMauro Carvalho Chehab 		},
820786baecfSMauro Carvalho Chehab 	},
821786baecfSMauro Carvalho Chehab 
822786baecfSMauro Carvalho Chehab 	.power_ctrl       = ttusb2_power_ctrl,
823786baecfSMauro Carvalho Chehab 	.identify_state   = ttusb2_identify_state,
824786baecfSMauro Carvalho Chehab 
825786baecfSMauro Carvalho Chehab 	.i2c_algo         = &ttusb2_i2c_algo,
826786baecfSMauro Carvalho Chehab 
827786baecfSMauro Carvalho Chehab 	.generic_bulk_ctrl_endpoint = 0x01,
828786baecfSMauro Carvalho Chehab 
829786baecfSMauro Carvalho Chehab 	.num_device_descs = 1,
830786baecfSMauro Carvalho Chehab 	.devices = {
831786baecfSMauro Carvalho Chehab 		{   "Technotrend TT-connect CT-3650",
832*5c1a56c9SMauro Carvalho Chehab 			.warm_ids = { &ttusb2_table[TECHNOTREND_CONNECT_CT3650], NULL },
833786baecfSMauro Carvalho Chehab 		},
834786baecfSMauro Carvalho Chehab 	}
835786baecfSMauro Carvalho Chehab };
836786baecfSMauro Carvalho Chehab 
837786baecfSMauro Carvalho Chehab static struct usb_driver ttusb2_driver = {
838786baecfSMauro Carvalho Chehab 	.name		= "dvb_usb_ttusb2",
839786baecfSMauro Carvalho Chehab 	.probe		= ttusb2_probe,
840786baecfSMauro Carvalho Chehab 	.disconnect	= ttusb2_usb_disconnect,
841786baecfSMauro Carvalho Chehab 	.id_table	= ttusb2_table,
842786baecfSMauro Carvalho Chehab };
843786baecfSMauro Carvalho Chehab 
844786baecfSMauro Carvalho Chehab module_usb_driver(ttusb2_driver);
845786baecfSMauro Carvalho Chehab 
84699e44da7SPatrick Boettcher MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
847786baecfSMauro Carvalho Chehab MODULE_DESCRIPTION("Driver for Pinnacle PCTV 400e DVB-S USB2.0");
848786baecfSMauro Carvalho Chehab MODULE_VERSION("1.0");
849786baecfSMauro Carvalho Chehab MODULE_LICENSE("GPL");
850