diff options
author | Jose Alberto Reguero <jareguero@telefonica.net> | 2012-03-04 17:22:05 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-03-19 13:15:16 -0400 |
commit | 962f8f67e48693d110c26d06089406dd9931474d (patch) | |
tree | 5628eb5a09797b861b300fbdfa17b7f9caaf7610 /drivers/media | |
parent | 266e8ae37daa04fb3d89759305659f4e0acbc126 (diff) |
[media] Add CI support to az6007 driver
This patch add CI support to az6007 driver.
Signed-off-by: Jose Alberto Reguero <jareguero@telefonica.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/dvb/dvb-usb/az6007.c | 377 |
1 files changed, 376 insertions, 1 deletions
diff --git a/drivers/media/dvb/dvb-usb/az6007.c b/drivers/media/dvb/dvb-usb/az6007.c index df4cbc0ed932..4008b9c50fbd 100644 --- a/drivers/media/dvb/dvb-usb/az6007.c +++ b/drivers/media/dvb/dvb-usb/az6007.c | |||
@@ -54,6 +54,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | |||
54 | 54 | ||
55 | struct az6007_device_state { | 55 | struct az6007_device_state { |
56 | struct mutex mutex; | 56 | struct mutex mutex; |
57 | struct mutex ca_mutex; | ||
57 | struct dvb_ca_en50221 ca; | 58 | struct dvb_ca_en50221 ca; |
58 | unsigned warm:1; | 59 | unsigned warm:1; |
59 | int (*gate_ctrl) (struct dvb_frontend *, int); | 60 | int (*gate_ctrl) (struct dvb_frontend *, int); |
@@ -218,6 +219,371 @@ static int az6007_rc_query(struct dvb_usb_device *d) | |||
218 | return 0; | 219 | return 0; |
219 | } | 220 | } |
220 | 221 | ||
222 | static int az6007_ci_read_attribute_mem(struct dvb_ca_en50221 *ca, | ||
223 | int slot, | ||
224 | int address) | ||
225 | { | ||
226 | struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; | ||
227 | struct az6007_device_state *state = (struct az6007_device_state *)d->priv; | ||
228 | |||
229 | int ret; | ||
230 | u8 req; | ||
231 | u16 value; | ||
232 | u16 index; | ||
233 | int blen; | ||
234 | u8 *b; | ||
235 | |||
236 | if (slot != 0) | ||
237 | return -EINVAL; | ||
238 | |||
239 | b = kmalloc(12, GFP_KERNEL); | ||
240 | if (!b) | ||
241 | return -ENOMEM; | ||
242 | |||
243 | mutex_lock(&state->ca_mutex); | ||
244 | |||
245 | req = 0xC1; | ||
246 | value = address; | ||
247 | index = 0; | ||
248 | blen = 1; | ||
249 | |||
250 | ret = az6007_read(d, req, value, index, b, blen); | ||
251 | if (ret < 0) { | ||
252 | warn("usb in operation failed. (%d)", ret); | ||
253 | ret = -EINVAL; | ||
254 | } else { | ||
255 | ret = b[0]; | ||
256 | } | ||
257 | |||
258 | mutex_unlock(&state->ca_mutex); | ||
259 | kfree(b); | ||
260 | return ret; | ||
261 | } | ||
262 | |||
263 | static int az6007_ci_write_attribute_mem(struct dvb_ca_en50221 *ca, | ||
264 | int slot, | ||
265 | int address, | ||
266 | u8 value) | ||
267 | { | ||
268 | struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; | ||
269 | struct az6007_device_state *state = (struct az6007_device_state *)d->priv; | ||
270 | |||
271 | int ret; | ||
272 | u8 req; | ||
273 | u16 value1; | ||
274 | u16 index; | ||
275 | int blen; | ||
276 | |||
277 | deb_info("%s %d", __func__, slot); | ||
278 | if (slot != 0) | ||
279 | return -EINVAL; | ||
280 | |||
281 | mutex_lock(&state->ca_mutex); | ||
282 | req = 0xC2; | ||
283 | value1 = address; | ||
284 | index = value; | ||
285 | blen = 0; | ||
286 | |||
287 | ret = az6007_write(d, req, value1, index, NULL, blen); | ||
288 | if (ret != 0) | ||
289 | warn("usb out operation failed. (%d)", ret); | ||
290 | |||
291 | mutex_unlock(&state->ca_mutex); | ||
292 | return ret; | ||
293 | } | ||
294 | |||
295 | static int az6007_ci_read_cam_control(struct dvb_ca_en50221 *ca, | ||
296 | int slot, | ||
297 | u8 address) | ||
298 | { | ||
299 | struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; | ||
300 | struct az6007_device_state *state = (struct az6007_device_state *)d->priv; | ||
301 | |||
302 | int ret; | ||
303 | u8 req; | ||
304 | u16 value; | ||
305 | u16 index; | ||
306 | int blen; | ||
307 | u8 *b; | ||
308 | |||
309 | if (slot != 0) | ||
310 | return -EINVAL; | ||
311 | |||
312 | b = kmalloc(12, GFP_KERNEL); | ||
313 | if (!b) | ||
314 | return -ENOMEM; | ||
315 | |||
316 | mutex_lock(&state->ca_mutex); | ||
317 | |||
318 | req = 0xC3; | ||
319 | value = address; | ||
320 | index = 0; | ||
321 | blen = 2; | ||
322 | |||
323 | ret = az6007_read(d, req, value, index, b, blen); | ||
324 | if (ret < 0) { | ||
325 | warn("usb in operation failed. (%d)", ret); | ||
326 | ret = -EINVAL; | ||
327 | } else { | ||
328 | if (b[0] == 0) | ||
329 | warn("Read CI IO error"); | ||
330 | |||
331 | ret = b[1]; | ||
332 | deb_info("read cam data = %x from 0x%x", b[1], value); | ||
333 | } | ||
334 | |||
335 | mutex_unlock(&state->ca_mutex); | ||
336 | kfree(b); | ||
337 | return ret; | ||
338 | } | ||
339 | |||
340 | static int az6007_ci_write_cam_control(struct dvb_ca_en50221 *ca, | ||
341 | int slot, | ||
342 | u8 address, | ||
343 | u8 value) | ||
344 | { | ||
345 | struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; | ||
346 | struct az6007_device_state *state = (struct az6007_device_state *)d->priv; | ||
347 | |||
348 | int ret; | ||
349 | u8 req; | ||
350 | u16 value1; | ||
351 | u16 index; | ||
352 | int blen; | ||
353 | |||
354 | if (slot != 0) | ||
355 | return -EINVAL; | ||
356 | |||
357 | mutex_lock(&state->ca_mutex); | ||
358 | req = 0xC4; | ||
359 | value1 = address; | ||
360 | index = value; | ||
361 | blen = 0; | ||
362 | |||
363 | ret = az6007_write(d, req, value1, index, NULL, blen); | ||
364 | if (ret != 0) { | ||
365 | warn("usb out operation failed. (%d)", ret); | ||
366 | goto failed; | ||
367 | } | ||
368 | |||
369 | failed: | ||
370 | mutex_unlock(&state->ca_mutex); | ||
371 | return ret; | ||
372 | } | ||
373 | |||
374 | static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot) | ||
375 | { | ||
376 | struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; | ||
377 | |||
378 | int ret; | ||
379 | u8 req; | ||
380 | u16 value; | ||
381 | u16 index; | ||
382 | int blen; | ||
383 | u8 *b; | ||
384 | |||
385 | b = kmalloc(12, GFP_KERNEL); | ||
386 | if (!b) | ||
387 | return -ENOMEM; | ||
388 | |||
389 | req = 0xC8; | ||
390 | value = 0; | ||
391 | index = 0; | ||
392 | blen = 1; | ||
393 | |||
394 | ret = az6007_read(d, req, value, index, b, blen); | ||
395 | if (ret < 0) { | ||
396 | warn("usb in operation failed. (%d)", ret); | ||
397 | ret = -EIO; | ||
398 | } else{ | ||
399 | ret = b[0]; | ||
400 | } | ||
401 | kfree(b); | ||
402 | return ret; | ||
403 | } | ||
404 | |||
405 | static int az6007_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot) | ||
406 | { | ||
407 | struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; | ||
408 | struct az6007_device_state *state = (struct az6007_device_state *)d->priv; | ||
409 | |||
410 | int ret, i; | ||
411 | u8 req; | ||
412 | u16 value; | ||
413 | u16 index; | ||
414 | int blen; | ||
415 | |||
416 | mutex_lock(&state->ca_mutex); | ||
417 | |||
418 | req = 0xC6; | ||
419 | value = 1; | ||
420 | index = 0; | ||
421 | blen = 0; | ||
422 | |||
423 | ret = az6007_write(d, req, value, index, NULL, blen); | ||
424 | if (ret != 0) { | ||
425 | warn("usb out operation failed. (%d)", ret); | ||
426 | goto failed; | ||
427 | } | ||
428 | |||
429 | msleep(500); | ||
430 | req = 0xC6; | ||
431 | value = 0; | ||
432 | index = 0; | ||
433 | blen = 0; | ||
434 | |||
435 | ret = az6007_write(d, req, value, index, NULL, blen); | ||
436 | if (ret != 0) { | ||
437 | warn("usb out operation failed. (%d)", ret); | ||
438 | goto failed; | ||
439 | } | ||
440 | |||
441 | for (i = 0; i < 15; i++) { | ||
442 | msleep(100); | ||
443 | |||
444 | if (CI_CamReady(ca, slot)) { | ||
445 | deb_info("CAM Ready"); | ||
446 | break; | ||
447 | } | ||
448 | } | ||
449 | msleep(5000); | ||
450 | |||
451 | failed: | ||
452 | mutex_unlock(&state->ca_mutex); | ||
453 | return ret; | ||
454 | } | ||
455 | |||
456 | static int az6007_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) | ||
457 | { | ||
458 | return 0; | ||
459 | } | ||
460 | |||
461 | static int az6007_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) | ||
462 | { | ||
463 | struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; | ||
464 | struct az6007_device_state *state = (struct az6007_device_state *)d->priv; | ||
465 | |||
466 | int ret; | ||
467 | u8 req; | ||
468 | u16 value; | ||
469 | u16 index; | ||
470 | int blen; | ||
471 | |||
472 | deb_info("%s", __func__); | ||
473 | mutex_lock(&state->ca_mutex); | ||
474 | req = 0xC7; | ||
475 | value = 1; | ||
476 | index = 0; | ||
477 | blen = 0; | ||
478 | |||
479 | ret = az6007_write(d, req, value, index, NULL, blen); | ||
480 | if (ret != 0) { | ||
481 | warn("usb out operation failed. (%d)", ret); | ||
482 | goto failed; | ||
483 | } | ||
484 | |||
485 | failed: | ||
486 | mutex_unlock(&state->ca_mutex); | ||
487 | return ret; | ||
488 | } | ||
489 | |||
490 | static int az6007_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) | ||
491 | { | ||
492 | struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data; | ||
493 | struct az6007_device_state *state = (struct az6007_device_state *)d->priv; | ||
494 | int ret; | ||
495 | u8 req; | ||
496 | u16 value; | ||
497 | u16 index; | ||
498 | int blen; | ||
499 | u8 *b; | ||
500 | |||
501 | b = kmalloc(12, GFP_KERNEL); | ||
502 | if (!b) | ||
503 | return -ENOMEM; | ||
504 | mutex_lock(&state->ca_mutex); | ||
505 | |||
506 | req = 0xC5; | ||
507 | value = 0; | ||
508 | index = 0; | ||
509 | blen = 1; | ||
510 | |||
511 | ret = az6007_read(d, req, value, index, b, blen); | ||
512 | if (ret < 0) { | ||
513 | warn("usb in operation failed. (%d)", ret); | ||
514 | ret = -EIO; | ||
515 | } else | ||
516 | ret = 0; | ||
517 | |||
518 | if (!ret && b[0] == 1) { | ||
519 | ret = DVB_CA_EN50221_POLL_CAM_PRESENT | | ||
520 | DVB_CA_EN50221_POLL_CAM_READY; | ||
521 | } | ||
522 | |||
523 | mutex_unlock(&state->ca_mutex); | ||
524 | kfree(b); | ||
525 | return ret; | ||
526 | } | ||
527 | |||
528 | |||
529 | static void az6007_ci_uninit(struct dvb_usb_device *d) | ||
530 | { | ||
531 | struct az6007_device_state *state; | ||
532 | |||
533 | deb_info("%s", __func__); | ||
534 | |||
535 | if (NULL == d) | ||
536 | return; | ||
537 | |||
538 | state = (struct az6007_device_state *)d->priv; | ||
539 | if (NULL == state) | ||
540 | return; | ||
541 | |||
542 | if (NULL == state->ca.data) | ||
543 | return; | ||
544 | |||
545 | dvb_ca_en50221_release(&state->ca); | ||
546 | |||
547 | memset(&state->ca, 0, sizeof(state->ca)); | ||
548 | } | ||
549 | |||
550 | |||
551 | static int az6007_ci_init(struct dvb_usb_adapter *a) | ||
552 | { | ||
553 | struct dvb_usb_device *d = a->dev; | ||
554 | struct az6007_device_state *state = (struct az6007_device_state *)d->priv; | ||
555 | int ret; | ||
556 | |||
557 | deb_info("%s", __func__); | ||
558 | |||
559 | mutex_init(&state->ca_mutex); | ||
560 | |||
561 | state->ca.owner = THIS_MODULE; | ||
562 | state->ca.read_attribute_mem = az6007_ci_read_attribute_mem; | ||
563 | state->ca.write_attribute_mem = az6007_ci_write_attribute_mem; | ||
564 | state->ca.read_cam_control = az6007_ci_read_cam_control; | ||
565 | state->ca.write_cam_control = az6007_ci_write_cam_control; | ||
566 | state->ca.slot_reset = az6007_ci_slot_reset; | ||
567 | state->ca.slot_shutdown = az6007_ci_slot_shutdown; | ||
568 | state->ca.slot_ts_enable = az6007_ci_slot_ts_enable; | ||
569 | state->ca.poll_slot_status = az6007_ci_poll_slot_status; | ||
570 | state->ca.data = d; | ||
571 | |||
572 | ret = dvb_ca_en50221_init(&a->dvb_adap, | ||
573 | &state->ca, | ||
574 | 0, /* flags */ | ||
575 | 1);/* n_slots */ | ||
576 | if (ret != 0) { | ||
577 | err("Cannot initialize CI: Error %d.", ret); | ||
578 | memset(&state->ca, 0, sizeof(state->ca)); | ||
579 | return ret; | ||
580 | } | ||
581 | |||
582 | deb_info("CI initialized."); | ||
583 | |||
584 | return 0; | ||
585 | } | ||
586 | |||
221 | static int az6007_read_mac_addr(struct dvb_usb_device *d, u8 mac[6]) | 587 | static int az6007_read_mac_addr(struct dvb_usb_device *d, u8 mac[6]) |
222 | { | 588 | { |
223 | struct az6007_device_state *st = d->priv; | 589 | struct az6007_device_state *st = d->priv; |
@@ -249,6 +615,8 @@ static int az6007_frontend_attach(struct dvb_usb_adapter *adap) | |||
249 | st->gate_ctrl = adap->fe_adap[0].fe->ops.i2c_gate_ctrl; | 615 | st->gate_ctrl = adap->fe_adap[0].fe->ops.i2c_gate_ctrl; |
250 | adap->fe_adap[0].fe->ops.i2c_gate_ctrl = drxk_gate_ctrl; | 616 | adap->fe_adap[0].fe->ops.i2c_gate_ctrl = drxk_gate_ctrl; |
251 | 617 | ||
618 | az6007_ci_init(adap); | ||
619 | |||
252 | return 0; | 620 | return 0; |
253 | } | 621 | } |
254 | 622 | ||
@@ -471,6 +839,13 @@ int az6007_identify_state(struct usb_device *udev, | |||
471 | 839 | ||
472 | static struct dvb_usb_device_properties az6007_properties; | 840 | static struct dvb_usb_device_properties az6007_properties; |
473 | 841 | ||
842 | static void az6007_usb_disconnect(struct usb_interface *intf) | ||
843 | { | ||
844 | struct dvb_usb_device *d = usb_get_intfdata(intf); | ||
845 | az6007_ci_uninit(d); | ||
846 | dvb_usb_device_exit(intf); | ||
847 | } | ||
848 | |||
474 | static int az6007_usb_probe(struct usb_interface *intf, | 849 | static int az6007_usb_probe(struct usb_interface *intf, |
475 | const struct usb_device_id *id) | 850 | const struct usb_device_id *id) |
476 | { | 851 | { |
@@ -546,7 +921,7 @@ static struct dvb_usb_device_properties az6007_properties = { | |||
546 | static struct usb_driver az6007_usb_driver = { | 921 | static struct usb_driver az6007_usb_driver = { |
547 | .name = "dvb_usb_az6007", | 922 | .name = "dvb_usb_az6007", |
548 | .probe = az6007_usb_probe, | 923 | .probe = az6007_usb_probe, |
549 | .disconnect = dvb_usb_device_exit, | 924 | .disconnect = az6007_usb_disconnect, |
550 | .id_table = az6007_usb_table, | 925 | .id_table = az6007_usb_table, |
551 | }; | 926 | }; |
552 | 927 | ||