diff options
author | Patrick Boettcher <pb@linuxtv.org> | 2006-12-02 18:16:04 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2006-12-10 06:05:03 -0500 |
commit | bc2e3913c786d7387e21ee0818c1a3b66a571703 (patch) | |
tree | 8ef6319697c9ef0123b5b671e05a6dfb678fbcca /drivers/media/dvb/dvb-usb/ttusb2.c | |
parent | 8949f1a2424a38a4080a2a3561a2698f215a7c4a (diff) |
V4L/DVB (4863): Adding support for Pinnacle PCTV 400e DVB-S
Adding support for Pinnacle PCTV 400e DVB-S. The module name is called ttusb2,
because it this device (and other Pinnacle devices) is using the USB-protocol
originally used by Technotrend device. I'm suspecting Technotrend as the
device-designer.
Signed-off-by: Patrick Boettcher <pb@linuxtv.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/dvb/dvb-usb/ttusb2.c')
-rw-r--r-- | drivers/media/dvb/dvb-usb/ttusb2.c | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/drivers/media/dvb/dvb-usb/ttusb2.c b/drivers/media/dvb/dvb-usb/ttusb2.c new file mode 100644 index 000000000000..95d29976ed78 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/ttusb2.c | |||
@@ -0,0 +1,270 @@ | |||
1 | /* DVB USB compliant linux driver for Technotrend DVB USB boxes and clones | ||
2 | * (e.g. Pinnacle 400e DVB-S USB2.0). | ||
3 | * | ||
4 | * The Pinnacle 400e uses the same protocol as the Technotrend USB1.1 boxes. | ||
5 | * | ||
6 | * TDA8263 + TDA10086 | ||
7 | * | ||
8 | * I2C addresses: | ||
9 | * 0x08 - LNBP21PD - LNB power supply | ||
10 | * 0x0e - TDA10086 - Demodulator | ||
11 | * 0x50 - FX2 eeprom | ||
12 | * 0x60 - TDA8263 - Tuner | ||
13 | * 0x78 ??? | ||
14 | * | ||
15 | * Copyright (c) 2002 Holger Waechtler <holger@convergence.de> | ||
16 | * Copyright (c) 2003 Felix Domke <tmbinc@elitedvb.net> | ||
17 | * Copyright (C) 2005-6 Patrick Boettcher <pb@linuxtv.org> | ||
18 | * | ||
19 | * This program is free software; you can redistribute it and/or modify it | ||
20 | * under the terms of the GNU General Public License as published by the Free | ||
21 | * Software Foundation, version 2. | ||
22 | * | ||
23 | * see Documentation/dvb/README.dvb-usb for more information | ||
24 | */ | ||
25 | #define DVB_USB_LOG_PREFIX "ttusb2" | ||
26 | #include "dvb-usb.h" | ||
27 | |||
28 | #include "ttusb2.h" | ||
29 | |||
30 | #include "tda826x.h" | ||
31 | #include "tda10086.h" | ||
32 | #include "lnbp21.h" | ||
33 | |||
34 | /* debug */ | ||
35 | static int dvb_usb_ttusb2_debug; | ||
36 | #define deb_info(args...) dprintk(dvb_usb_ttusb2_debug,0x01,args) | ||
37 | module_param_named(debug,dvb_usb_ttusb2_debug, int, 0644); | ||
38 | MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))." DVB_USB_DEBUG_STATUS); | ||
39 | |||
40 | struct ttusb2_state { | ||
41 | u8 id; | ||
42 | }; | ||
43 | |||
44 | static int ttusb2_msg(struct dvb_usb_device *d, u8 cmd, | ||
45 | u8 *wbuf, int wlen, u8 *rbuf, int rlen) | ||
46 | { | ||
47 | struct ttusb2_state *st = d->priv; | ||
48 | u8 s[wlen+4],r[64] = { 0 }; | ||
49 | int ret = 0; | ||
50 | |||
51 | memset(s,0,wlen+4); | ||
52 | |||
53 | s[0] = 0xaa; | ||
54 | s[1] = ++st->id; | ||
55 | s[2] = cmd; | ||
56 | s[3] = wlen; | ||
57 | memcpy(&s[4],wbuf,wlen); | ||
58 | |||
59 | ret = dvb_usb_generic_rw(d, s, wlen+4, r, 64, 0); | ||
60 | |||
61 | if (ret != 0 || | ||
62 | r[0] != 0x55 || | ||
63 | r[1] != s[1] || | ||
64 | r[2] != cmd || | ||
65 | (rlen > 0 && r[3] != rlen)) { | ||
66 | warn("there might have been an error during control message transfer. (rlen = %d, was %d)",rlen,r[3]); | ||
67 | return -EIO; | ||
68 | } | ||
69 | |||
70 | if (rlen > 0) | ||
71 | memcpy(rbuf, &r[4], rlen); | ||
72 | |||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) | ||
77 | { | ||
78 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | ||
79 | static u8 obuf[60], ibuf[60]; | ||
80 | int i,read; | ||
81 | |||
82 | if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | ||
83 | return -EAGAIN; | ||
84 | |||
85 | if (num > 2) | ||
86 | warn("more than 2 i2c messages at a time is not handled yet. TODO."); | ||
87 | |||
88 | for (i = 0; i < num; i++) { | ||
89 | read = i+1 < num && (msg[i+1].flags & I2C_M_RD); | ||
90 | |||
91 | obuf[0] = (msg[i].addr << 1) | read; | ||
92 | obuf[1] = msg[i].len; | ||
93 | |||
94 | /* read request */ | ||
95 | if (read) | ||
96 | obuf[2] = msg[i+1].len; | ||
97 | else | ||
98 | obuf[2] = 0; | ||
99 | |||
100 | memcpy(&obuf[3],msg[i].buf,msg[i].len); | ||
101 | |||
102 | if (ttusb2_msg(d, CMD_I2C_XFER, obuf, msg[i].len+3, ibuf, obuf[2] + 3) < 0) { | ||
103 | err("i2c transfer failed."); | ||
104 | break; | ||
105 | } | ||
106 | |||
107 | if (read) { | ||
108 | memcpy(msg[i+1].buf,&ibuf[3],msg[i+1].len); | ||
109 | i++; | ||
110 | } | ||
111 | } | ||
112 | |||
113 | mutex_unlock(&d->i2c_mutex); | ||
114 | return i; | ||
115 | } | ||
116 | |||
117 | static u32 ttusb2_i2c_func(struct i2c_adapter *adapter) | ||
118 | { | ||
119 | return I2C_FUNC_I2C; | ||
120 | } | ||
121 | |||
122 | static struct i2c_algorithm ttusb2_i2c_algo = { | ||
123 | .master_xfer = ttusb2_i2c_xfer, | ||
124 | .functionality = ttusb2_i2c_func, | ||
125 | }; | ||
126 | |||
127 | /* Callbacks for DVB USB */ | ||
128 | static int ttusb2_identify_state (struct usb_device *udev, struct | ||
129 | dvb_usb_device_properties *props, struct dvb_usb_device_description **desc, | ||
130 | int *cold) | ||
131 | { | ||
132 | *cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0; | ||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | static int ttusb2_power_ctrl(struct dvb_usb_device *d, int onoff) | ||
137 | { | ||
138 | u8 b = onoff; | ||
139 | ttusb2_msg(d, CMD_POWER, &b, 0, NULL, 0); | ||
140 | return ttusb2_msg(d, CMD_POWER, &b, 1, NULL, 0); | ||
141 | } | ||
142 | |||
143 | |||
144 | static struct tda10086_config tda10086_config = { | ||
145 | .demod_address = 0x0e, | ||
146 | .invert = 0, | ||
147 | }; | ||
148 | |||
149 | static int ttusb2_frontend_attach(struct dvb_usb_adapter *adap) | ||
150 | { | ||
151 | if (usb_set_interface(adap->dev->udev,0,3) < 0) | ||
152 | err("set interface to alts=3 failed"); | ||
153 | |||
154 | if ((adap->fe = dvb_attach(tda10086_attach, &tda10086_config, &adap->dev->i2c_adap)) == NULL) { | ||
155 | deb_info("TDA10086 attach failed\n"); | ||
156 | return -ENODEV; | ||
157 | } | ||
158 | |||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | static int ttusb2_tuner_attach(struct dvb_usb_adapter *adap) | ||
163 | { | ||
164 | if (dvb_attach(tda826x_attach, adap->fe, 0x60, &adap->dev->i2c_adap, 0) == NULL) { | ||
165 | deb_info("TDA8263 attach failed\n"); | ||
166 | return -ENODEV; | ||
167 | } | ||
168 | |||
169 | if (dvb_attach(lnbp21_attach, adap->fe, &adap->dev->i2c_adap, 0, 0) == NULL) { | ||
170 | deb_info("LNBP21 attach failed\n"); | ||
171 | return -ENODEV; | ||
172 | } | ||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | /* DVB USB Driver stuff */ | ||
177 | static struct dvb_usb_device_properties ttusb2_properties; | ||
178 | |||
179 | static int ttusb2_probe(struct usb_interface *intf, | ||
180 | const struct usb_device_id *id) | ||
181 | { | ||
182 | return dvb_usb_device_init(intf,&ttusb2_properties,THIS_MODULE,NULL); | ||
183 | } | ||
184 | |||
185 | static struct usb_device_id ttusb2_table [] = { | ||
186 | { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_400E) }, | ||
187 | {} /* Terminating entry */ | ||
188 | }; | ||
189 | MODULE_DEVICE_TABLE (usb, ttusb2_table); | ||
190 | |||
191 | static struct dvb_usb_device_properties ttusb2_properties = { | ||
192 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | ||
193 | |||
194 | .usb_ctrl = CYPRESS_FX2, | ||
195 | .firmware = "dvb-usb-pctv-400e-01.fw", | ||
196 | |||
197 | .size_of_priv = sizeof(struct ttusb2_state), | ||
198 | |||
199 | .num_adapters = 1, | ||
200 | .adapter = { | ||
201 | { | ||
202 | .streaming_ctrl = NULL, // ttusb2_streaming_ctrl, | ||
203 | |||
204 | .frontend_attach = ttusb2_frontend_attach, | ||
205 | .tuner_attach = ttusb2_tuner_attach, | ||
206 | |||
207 | /* parameter for the MPEG2-data transfer */ | ||
208 | .stream = { | ||
209 | .type = USB_ISOC, | ||
210 | .count = 5, | ||
211 | .endpoint = 0x02, | ||
212 | .u = { | ||
213 | .isoc = { | ||
214 | .framesperurb = 4, | ||
215 | .framesize = 940, | ||
216 | .interval = 1, | ||
217 | } | ||
218 | } | ||
219 | } | ||
220 | } | ||
221 | }, | ||
222 | |||
223 | .power_ctrl = ttusb2_power_ctrl, | ||
224 | .identify_state = ttusb2_identify_state, | ||
225 | |||
226 | .i2c_algo = &ttusb2_i2c_algo, | ||
227 | |||
228 | .generic_bulk_ctrl_endpoint = 0x01, | ||
229 | |||
230 | .num_device_descs = 1, | ||
231 | .devices = { | ||
232 | { "Pinnacle 400e DVB-S USB2.0", | ||
233 | { &ttusb2_table[0], NULL }, | ||
234 | { NULL }, | ||
235 | }, | ||
236 | } | ||
237 | }; | ||
238 | |||
239 | static struct usb_driver ttusb2_driver = { | ||
240 | .name = "dvb_usb_ttusb2", | ||
241 | .probe = ttusb2_probe, | ||
242 | .disconnect = dvb_usb_device_exit, | ||
243 | .id_table = ttusb2_table, | ||
244 | }; | ||
245 | |||
246 | /* module stuff */ | ||
247 | static int __init ttusb2_module_init(void) | ||
248 | { | ||
249 | int result; | ||
250 | if ((result = usb_register(&ttusb2_driver))) { | ||
251 | err("usb_register failed. Error number %d",result); | ||
252 | return result; | ||
253 | } | ||
254 | |||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | static void __exit ttusb2_module_exit(void) | ||
259 | { | ||
260 | /* deregister this driver from the USB subsystem */ | ||
261 | usb_deregister(&ttusb2_driver); | ||
262 | } | ||
263 | |||
264 | module_init (ttusb2_module_init); | ||
265 | module_exit (ttusb2_module_exit); | ||
266 | |||
267 | MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>"); | ||
268 | MODULE_DESCRIPTION("Driver for Pinnacle PCTV 400e DVB-S USB2.0"); | ||
269 | MODULE_VERSION("1.0"); | ||
270 | MODULE_LICENSE("GPL"); | ||