firedtv-ci.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. /*
  2. * FireDTV driver (formerly known as FireSAT)
  3. *
  4. * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
  5. * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License as
  9. * published by the Free Software Foundation; either version 2 of
  10. * the License, or (at your option) any later version.
  11. */
  12. #include <linux/device.h>
  13. #include <linux/dvb/ca.h>
  14. #include <linux/fs.h>
  15. #include <linux/module.h>
  16. #include <media/dvbdev.h>
  17. #include "firedtv.h"
  18. #define EN50221_TAG_APP_INFO_ENQUIRY 0x9f8020
  19. #define EN50221_TAG_CA_INFO_ENQUIRY 0x9f8030
  20. #define EN50221_TAG_CA_PMT 0x9f8032
  21. #define EN50221_TAG_ENTER_MENU 0x9f8022
  22. static int fdtv_ca_ready(struct firedtv_tuner_status *stat)
  23. {
  24. return stat->ca_initialization_status == 1 &&
  25. stat->ca_error_flag == 0 &&
  26. stat->ca_dvb_flag == 1 &&
  27. stat->ca_module_present_status == 1;
  28. }
  29. static int fdtv_get_ca_flags(struct firedtv_tuner_status *stat)
  30. {
  31. int flags = 0;
  32. if (stat->ca_module_present_status == 1)
  33. flags |= CA_CI_MODULE_PRESENT;
  34. if (stat->ca_initialization_status == 1 &&
  35. stat->ca_error_flag == 0 &&
  36. stat->ca_dvb_flag == 1)
  37. flags |= CA_CI_MODULE_READY;
  38. return flags;
  39. }
  40. static int fdtv_ca_get_caps(void *arg)
  41. {
  42. struct ca_caps *cap = arg;
  43. cap->slot_num = 1;
  44. cap->slot_type = CA_CI;
  45. cap->descr_num = 1;
  46. cap->descr_type = CA_ECD;
  47. return 0;
  48. }
  49. static int fdtv_ca_get_slot_info(struct firedtv *fdtv, void *arg)
  50. {
  51. struct firedtv_tuner_status stat;
  52. struct ca_slot_info *slot = arg;
  53. int err;
  54. err = avc_tuner_status(fdtv, &stat);
  55. if (err)
  56. return err;
  57. if (slot->num != 0)
  58. return -EACCES;
  59. slot->type = CA_CI;
  60. slot->flags = fdtv_get_ca_flags(&stat);
  61. return 0;
  62. }
  63. static int fdtv_ca_app_info(struct firedtv *fdtv, void *arg)
  64. {
  65. struct ca_msg *reply = arg;
  66. return avc_ca_app_info(fdtv, reply->msg, &reply->length);
  67. }
  68. static int fdtv_ca_info(struct firedtv *fdtv, void *arg)
  69. {
  70. struct ca_msg *reply = arg;
  71. return avc_ca_info(fdtv, reply->msg, &reply->length);
  72. }
  73. static int fdtv_ca_get_mmi(struct firedtv *fdtv, void *arg)
  74. {
  75. struct ca_msg *reply = arg;
  76. return avc_ca_get_mmi(fdtv, reply->msg, &reply->length);
  77. }
  78. static int fdtv_ca_get_msg(struct firedtv *fdtv, void *arg)
  79. {
  80. struct firedtv_tuner_status stat;
  81. int err;
  82. switch (fdtv->ca_last_command) {
  83. case EN50221_TAG_APP_INFO_ENQUIRY:
  84. err = fdtv_ca_app_info(fdtv, arg);
  85. break;
  86. case EN50221_TAG_CA_INFO_ENQUIRY:
  87. err = fdtv_ca_info(fdtv, arg);
  88. break;
  89. default:
  90. err = avc_tuner_status(fdtv, &stat);
  91. if (err)
  92. break;
  93. if (stat.ca_mmi == 1)
  94. err = fdtv_ca_get_mmi(fdtv, arg);
  95. else {
  96. dev_info(fdtv->device, "unhandled CA message 0x%08x\n",
  97. fdtv->ca_last_command);
  98. err = -EACCES;
  99. }
  100. }
  101. fdtv->ca_last_command = 0;
  102. return err;
  103. }
  104. static int fdtv_ca_pmt(struct firedtv *fdtv, void *arg)
  105. {
  106. struct ca_msg *msg = arg;
  107. int data_pos;
  108. int data_length;
  109. int i;
  110. data_pos = 4;
  111. if (msg->msg[3] & 0x80) {
  112. data_length = 0;
  113. for (i = 0; i < (msg->msg[3] & 0x7f); i++)
  114. data_length = (data_length << 8) + msg->msg[data_pos++];
  115. } else {
  116. data_length = msg->msg[3];
  117. }
  118. return avc_ca_pmt(fdtv, &msg->msg[data_pos], data_length);
  119. }
  120. static int fdtv_ca_send_msg(struct firedtv *fdtv, void *arg)
  121. {
  122. struct ca_msg *msg = arg;
  123. int err;
  124. /* Do we need a semaphore for this? */
  125. fdtv->ca_last_command =
  126. (msg->msg[0] << 16) + (msg->msg[1] << 8) + msg->msg[2];
  127. switch (fdtv->ca_last_command) {
  128. case EN50221_TAG_CA_PMT:
  129. err = fdtv_ca_pmt(fdtv, arg);
  130. break;
  131. case EN50221_TAG_APP_INFO_ENQUIRY:
  132. /* handled in ca_get_msg */
  133. err = 0;
  134. break;
  135. case EN50221_TAG_CA_INFO_ENQUIRY:
  136. /* handled in ca_get_msg */
  137. err = 0;
  138. break;
  139. case EN50221_TAG_ENTER_MENU:
  140. err = avc_ca_enter_menu(fdtv);
  141. break;
  142. default:
  143. dev_err(fdtv->device, "unhandled CA message 0x%08x\n",
  144. fdtv->ca_last_command);
  145. err = -EACCES;
  146. }
  147. return err;
  148. }
  149. static int fdtv_ca_ioctl(struct file *file, unsigned int cmd, void *arg)
  150. {
  151. struct dvb_device *dvbdev = file->private_data;
  152. struct firedtv *fdtv = dvbdev->priv;
  153. struct firedtv_tuner_status stat;
  154. int err;
  155. switch (cmd) {
  156. case CA_RESET:
  157. err = avc_ca_reset(fdtv);
  158. break;
  159. case CA_GET_CAP:
  160. err = fdtv_ca_get_caps(arg);
  161. break;
  162. case CA_GET_SLOT_INFO:
  163. err = fdtv_ca_get_slot_info(fdtv, arg);
  164. break;
  165. case CA_GET_MSG:
  166. err = fdtv_ca_get_msg(fdtv, arg);
  167. break;
  168. case CA_SEND_MSG:
  169. err = fdtv_ca_send_msg(fdtv, arg);
  170. break;
  171. default:
  172. dev_info(fdtv->device, "unhandled CA ioctl %u\n", cmd);
  173. err = -EOPNOTSUPP;
  174. }
  175. /* FIXME Is this necessary? */
  176. avc_tuner_status(fdtv, &stat);
  177. return err;
  178. }
  179. static __poll_t fdtv_ca_io_poll(struct file *file, poll_table *wait)
  180. {
  181. return EPOLLIN;
  182. }
  183. static const struct file_operations fdtv_ca_fops = {
  184. .owner = THIS_MODULE,
  185. .unlocked_ioctl = dvb_generic_ioctl,
  186. .open = dvb_generic_open,
  187. .release = dvb_generic_release,
  188. .poll = fdtv_ca_io_poll,
  189. .llseek = noop_llseek,
  190. };
  191. static struct dvb_device fdtv_ca = {
  192. .users = 1,
  193. .readers = 1,
  194. .writers = 1,
  195. .fops = &fdtv_ca_fops,
  196. .kernel_ioctl = fdtv_ca_ioctl,
  197. };
  198. int fdtv_ca_register(struct firedtv *fdtv)
  199. {
  200. struct firedtv_tuner_status stat;
  201. int err;
  202. if (avc_tuner_status(fdtv, &stat))
  203. return -EINVAL;
  204. if (!fdtv_ca_ready(&stat))
  205. return -EFAULT;
  206. err = dvb_register_device(&fdtv->adapter, &fdtv->cadev,
  207. &fdtv_ca, fdtv, DVB_DEVICE_CA, 0);
  208. if (stat.ca_application_info == 0)
  209. dev_err(fdtv->device, "CaApplicationInfo is not set\n");
  210. if (stat.ca_date_time_request == 1)
  211. avc_ca_get_time_date(fdtv, &fdtv->ca_time_interval);
  212. return err;
  213. }
  214. void fdtv_ca_release(struct firedtv *fdtv)
  215. {
  216. dvb_unregister_device(fdtv->cadev);
  217. }