diff options
author | Jose Alberto Reguero <jareguero@telefonica.net> | 2011-09-18 06:59:05 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-09-23 22:07:35 -0400 |
commit | 8c0bc03c80952e81db8cb11082c0c6375e9083ab (patch) | |
tree | 3e19d69b601652924b46f9d67d03996a3185f3f9 /drivers/media/dvb/dvb-usb/ttusb2.c | |
parent | 1cd7acc4ef5459dd92d0d04430d353de0a54b393 (diff) |
[media] ttusb2: TT CT-3650 CI support
Signed-off-by: Jose Alberto Reguero <jareguero@telefonica.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/dvb/dvb-usb/ttusb2.c')
-rw-r--r-- | drivers/media/dvb/dvb-usb/ttusb2.c | 284 |
1 files changed, 283 insertions, 1 deletions
diff --git a/drivers/media/dvb/dvb-usb/ttusb2.c b/drivers/media/dvb/dvb-usb/ttusb2.c index 7b07cf655387..ea4eab8b3965 100644 --- a/drivers/media/dvb/dvb-usb/ttusb2.c +++ b/drivers/media/dvb/dvb-usb/ttusb2.c | |||
@@ -33,16 +33,40 @@ | |||
33 | #include "tda10048.h" | 33 | #include "tda10048.h" |
34 | #include "tda827x.h" | 34 | #include "tda827x.h" |
35 | #include "lnbp21.h" | 35 | #include "lnbp21.h" |
36 | /* CA */ | ||
37 | #include "dvb_ca_en50221.h" | ||
36 | 38 | ||
37 | /* debug */ | 39 | /* debug */ |
38 | static int dvb_usb_ttusb2_debug; | 40 | static int dvb_usb_ttusb2_debug; |
39 | #define deb_info(args...) dprintk(dvb_usb_ttusb2_debug,0x01,args) | 41 | #define deb_info(args...) dprintk(dvb_usb_ttusb2_debug,0x01,args) |
40 | module_param_named(debug,dvb_usb_ttusb2_debug, int, 0644); | 42 | module_param_named(debug,dvb_usb_ttusb2_debug, int, 0644); |
41 | MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))." DVB_USB_DEBUG_STATUS); | 43 | MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))." DVB_USB_DEBUG_STATUS); |
44 | static int dvb_usb_ttusb2_debug_ci; | ||
45 | module_param_named(debug_ci,dvb_usb_ttusb2_debug_ci, int, 0644); | ||
46 | MODULE_PARM_DESC(debug_ci, "set debugging ci." DVB_USB_DEBUG_STATUS); | ||
42 | 47 | ||
43 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | 48 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); |
44 | 49 | ||
50 | #define ci_dbg(format, arg...) \ | ||
51 | do { \ | ||
52 | if (dvb_usb_ttusb2_debug_ci) \ | ||
53 | printk(KERN_DEBUG DVB_USB_LOG_PREFIX \ | ||
54 | ": %s " format "\n" , __func__, ## arg); \ | ||
55 | } while (0) | ||
56 | |||
57 | enum { | ||
58 | TT3650_CMD_CI_TEST = 0x40, | ||
59 | TT3650_CMD_CI_RD_CTRL, | ||
60 | TT3650_CMD_CI_WR_CTRL, | ||
61 | TT3650_CMD_CI_RD_ATTR, | ||
62 | TT3650_CMD_CI_WR_ATTR, | ||
63 | TT3650_CMD_CI_RESET, | ||
64 | TT3650_CMD_CI_SET_VIDEO_PORT | ||
65 | }; | ||
66 | |||
45 | struct ttusb2_state { | 67 | struct ttusb2_state { |
68 | struct dvb_ca_en50221 ca; | ||
69 | struct mutex ca_mutex; | ||
46 | u8 id; | 70 | u8 id; |
47 | u16 last_rc_key; | 71 | u16 last_rc_key; |
48 | }; | 72 | }; |
@@ -79,6 +103,255 @@ static int ttusb2_msg(struct dvb_usb_device *d, u8 cmd, | |||
79 | return 0; | 103 | return 0; |
80 | } | 104 | } |
81 | 105 | ||
106 | /* ci */ | ||
107 | static int tt3650_ci_msg(struct dvb_usb_device *d, u8 cmd, u8 *data, unsigned int write_len, unsigned int read_len) | ||
108 | { | ||
109 | int ret; | ||
110 | u8 rx[60];/* (64 -4) */ | ||
111 | ret = ttusb2_msg(d, cmd, data, write_len, rx, read_len); | ||
112 | if (!ret) | ||
113 | memcpy(data, rx, read_len); | ||
114 | return ret; | ||
115 | } | ||
116 | |||
117 | static int tt3650_ci_msg_locked(struct dvb_ca_en50221 *ca, u8 cmd, u8 *data, unsigned int write_len, unsigned int read_len) | ||
118 | { | ||
119 | struct dvb_usb_device *d = ca->data; | ||
120 | struct ttusb2_state *state = d->priv; | ||
121 | int ret; | ||
122 | |||
123 | mutex_lock(&state->ca_mutex); | ||
124 | ret = tt3650_ci_msg(d, cmd, data, write_len, read_len); | ||
125 | mutex_unlock(&state->ca_mutex); | ||
126 | |||
127 | return ret; | ||
128 | } | ||
129 | |||
130 | static int tt3650_ci_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address) | ||
131 | { | ||
132 | u8 buf[3]; | ||
133 | int ret = 0; | ||
134 | |||
135 | if (slot) | ||
136 | return -EINVAL; | ||
137 | |||
138 | buf[0] = (address >> 8) & 0x0F; | ||
139 | buf[1] = address; | ||
140 | |||
141 | |||
142 | ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_ATTR, buf, 2, 3); | ||
143 | |||
144 | ci_dbg("%04x -> %d 0x%02x", address, ret, buf[2]); | ||
145 | |||
146 | if (ret < 0) | ||
147 | return ret; | ||
148 | |||
149 | return buf[2]; | ||
150 | } | ||
151 | |||
152 | static int tt3650_ci_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value) | ||
153 | { | ||
154 | u8 buf[3]; | ||
155 | |||
156 | ci_dbg("%d 0x%04x 0x%02x", slot, address, value); | ||
157 | |||
158 | if (slot) | ||
159 | return -EINVAL; | ||
160 | |||
161 | buf[0] = (address >> 8) & 0x0F; | ||
162 | buf[1] = address; | ||
163 | buf[2] = value; | ||
164 | |||
165 | return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_ATTR, buf, 3, 3); | ||
166 | } | ||
167 | |||
168 | static int tt3650_ci_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address) | ||
169 | { | ||
170 | u8 buf[2]; | ||
171 | int ret; | ||
172 | |||
173 | if (slot) | ||
174 | return -EINVAL; | ||
175 | |||
176 | buf[0] = address & 3; | ||
177 | |||
178 | ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_RD_CTRL, buf, 1, 2); | ||
179 | |||
180 | ci_dbg("0x%02x -> %d 0x%02x", address, ret, buf[1]); | ||
181 | |||
182 | if (ret < 0) | ||
183 | return ret; | ||
184 | |||
185 | return buf[1]; | ||
186 | } | ||
187 | |||
188 | static int tt3650_ci_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value) | ||
189 | { | ||
190 | u8 buf[2]; | ||
191 | |||
192 | ci_dbg("%d 0x%02x 0x%02x", slot, address, value); | ||
193 | |||
194 | if (slot) | ||
195 | return -EINVAL; | ||
196 | |||
197 | buf[0] = address; | ||
198 | buf[1] = value; | ||
199 | |||
200 | return tt3650_ci_msg_locked(ca, TT3650_CMD_CI_WR_CTRL, buf, 2, 2); | ||
201 | } | ||
202 | |||
203 | static int tt3650_ci_set_video_port(struct dvb_ca_en50221 *ca, int slot, int enable) | ||
204 | { | ||
205 | u8 buf[1]; | ||
206 | int ret; | ||
207 | |||
208 | ci_dbg("%d %d", slot, enable); | ||
209 | |||
210 | if (slot) | ||
211 | return -EINVAL; | ||
212 | |||
213 | buf[0] = enable; | ||
214 | |||
215 | ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1); | ||
216 | if (ret < 0) | ||
217 | return ret; | ||
218 | |||
219 | if (enable != buf[0]) { | ||
220 | err("CI not %sabled.", enable ? "en" : "dis"); | ||
221 | return -EIO; | ||
222 | } | ||
223 | |||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | static int tt3650_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) | ||
228 | { | ||
229 | return tt3650_ci_set_video_port(ca, slot, 0); | ||
230 | } | ||
231 | |||
232 | static int tt3650_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) | ||
233 | { | ||
234 | return tt3650_ci_set_video_port(ca, slot, 1); | ||
235 | } | ||
236 | |||
237 | static int tt3650_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot) | ||
238 | { | ||
239 | struct dvb_usb_device *d = ca->data; | ||
240 | struct ttusb2_state *state = d->priv; | ||
241 | u8 buf[1]; | ||
242 | int ret; | ||
243 | |||
244 | ci_dbg("%d", slot); | ||
245 | |||
246 | if (slot) | ||
247 | return -EINVAL; | ||
248 | |||
249 | buf[0] = 0; | ||
250 | |||
251 | mutex_lock(&state->ca_mutex); | ||
252 | |||
253 | ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1); | ||
254 | if (ret) | ||
255 | goto failed; | ||
256 | |||
257 | msleep(500); | ||
258 | |||
259 | buf[0] = 1; | ||
260 | |||
261 | ret = tt3650_ci_msg(d, TT3650_CMD_CI_RESET, buf, 1, 1); | ||
262 | if (ret) | ||
263 | goto failed; | ||
264 | |||
265 | msleep(500); | ||
266 | |||
267 | buf[0] = 0; /* FTA */ | ||
268 | |||
269 | ret = tt3650_ci_msg(d, TT3650_CMD_CI_SET_VIDEO_PORT, buf, 1, 1); | ||
270 | |||
271 | msleep(1100); | ||
272 | |||
273 | failed: | ||
274 | mutex_unlock(&state->ca_mutex); | ||
275 | |||
276 | return ret; | ||
277 | } | ||
278 | |||
279 | static int tt3650_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) | ||
280 | { | ||
281 | u8 buf[1]; | ||
282 | int ret; | ||
283 | |||
284 | if (slot) | ||
285 | return -EINVAL; | ||
286 | |||
287 | ret = tt3650_ci_msg_locked(ca, TT3650_CMD_CI_TEST, buf, 0, 1); | ||
288 | if (ret) | ||
289 | return ret; | ||
290 | |||
291 | if (1 == buf[0]) { | ||
292 | return DVB_CA_EN50221_POLL_CAM_PRESENT | | ||
293 | DVB_CA_EN50221_POLL_CAM_READY; | ||
294 | } | ||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | static void tt3650_ci_uninit(struct dvb_usb_device *d) | ||
299 | { | ||
300 | struct ttusb2_state *state; | ||
301 | |||
302 | ci_dbg(""); | ||
303 | |||
304 | if (NULL == d) | ||
305 | return; | ||
306 | |||
307 | state = d->priv; | ||
308 | if (NULL == state) | ||
309 | return; | ||
310 | |||
311 | if (NULL == state->ca.data) | ||
312 | return; | ||
313 | |||
314 | dvb_ca_en50221_release(&state->ca); | ||
315 | |||
316 | memset(&state->ca, 0, sizeof(state->ca)); | ||
317 | } | ||
318 | |||
319 | static int tt3650_ci_init(struct dvb_usb_adapter *a) | ||
320 | { | ||
321 | struct dvb_usb_device *d = a->dev; | ||
322 | struct ttusb2_state *state = d->priv; | ||
323 | int ret; | ||
324 | |||
325 | ci_dbg(""); | ||
326 | |||
327 | mutex_init(&state->ca_mutex); | ||
328 | |||
329 | state->ca.owner = THIS_MODULE; | ||
330 | state->ca.read_attribute_mem = tt3650_ci_read_attribute_mem; | ||
331 | state->ca.write_attribute_mem = tt3650_ci_write_attribute_mem; | ||
332 | state->ca.read_cam_control = tt3650_ci_read_cam_control; | ||
333 | state->ca.write_cam_control = tt3650_ci_write_cam_control; | ||
334 | state->ca.slot_reset = tt3650_ci_slot_reset; | ||
335 | state->ca.slot_shutdown = tt3650_ci_slot_shutdown; | ||
336 | state->ca.slot_ts_enable = tt3650_ci_slot_ts_enable; | ||
337 | state->ca.poll_slot_status = tt3650_ci_poll_slot_status; | ||
338 | state->ca.data = d; | ||
339 | |||
340 | ret = dvb_ca_en50221_init(&a->dvb_adap, | ||
341 | &state->ca, | ||
342 | /* flags */ 0, | ||
343 | /* n_slots */ 1); | ||
344 | if (ret) { | ||
345 | err("Cannot initialize CI: Error %d.", ret); | ||
346 | memset(&state->ca, 0, sizeof(state->ca)); | ||
347 | return ret; | ||
348 | } | ||
349 | |||
350 | info("CI initialized."); | ||
351 | |||
352 | return 0; | ||
353 | } | ||
354 | |||
82 | static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) | 355 | static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) |
83 | { | 356 | { |
84 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | 357 | struct dvb_usb_device *d = i2c_get_adapdata(adap); |
@@ -251,6 +524,7 @@ static int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap) | |||
251 | deb_info("TDA10023 attach failed\n"); | 524 | deb_info("TDA10023 attach failed\n"); |
252 | return -ENODEV; | 525 | return -ENODEV; |
253 | } | 526 | } |
527 | tt3650_ci_init(adap); | ||
254 | } else { | 528 | } else { |
255 | adap->fe_adap[1].fe = dvb_attach(tda10048_attach, | 529 | adap->fe_adap[1].fe = dvb_attach(tda10048_attach, |
256 | &tda10048_config, &adap->dev->i2c_adap); | 530 | &tda10048_config, &adap->dev->i2c_adap); |
@@ -305,6 +579,14 @@ static struct dvb_usb_device_properties ttusb2_properties; | |||
305 | static struct dvb_usb_device_properties ttusb2_properties_s2400; | 579 | static struct dvb_usb_device_properties ttusb2_properties_s2400; |
306 | static struct dvb_usb_device_properties ttusb2_properties_ct3650; | 580 | static struct dvb_usb_device_properties ttusb2_properties_ct3650; |
307 | 581 | ||
582 | static void ttusb2_usb_disconnect(struct usb_interface *intf) | ||
583 | { | ||
584 | struct dvb_usb_device *d = usb_get_intfdata(intf); | ||
585 | |||
586 | tt3650_ci_uninit(d); | ||
587 | dvb_usb_device_exit(intf); | ||
588 | } | ||
589 | |||
308 | static int ttusb2_probe(struct usb_interface *intf, | 590 | static int ttusb2_probe(struct usb_interface *intf, |
309 | const struct usb_device_id *id) | 591 | const struct usb_device_id *id) |
310 | { | 592 | { |
@@ -513,7 +795,7 @@ static struct dvb_usb_device_properties ttusb2_properties_ct3650 = { | |||
513 | static struct usb_driver ttusb2_driver = { | 795 | static struct usb_driver ttusb2_driver = { |
514 | .name = "dvb_usb_ttusb2", | 796 | .name = "dvb_usb_ttusb2", |
515 | .probe = ttusb2_probe, | 797 | .probe = ttusb2_probe, |
516 | .disconnect = dvb_usb_device_exit, | 798 | .disconnect = ttusb2_usb_disconnect, |
517 | .id_table = ttusb2_table, | 799 | .id_table = ttusb2_table, |
518 | }; | 800 | }; |
519 | 801 | ||