firesat-ci.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  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/dvb/ca.h>
  13. #include <linux/fs.h>
  14. #include <linux/module.h>
  15. #include <dvbdev.h>
  16. #include "avc_api.h"
  17. #include "firesat.h"
  18. #include "firesat-ci.h"
  19. static unsigned int ca_debug = 0;
  20. module_param(ca_debug, int, 0644);
  21. MODULE_PARM_DESC(ca_debug, "debug logging of ca system, default is 0 (no)");
  22. static int firesat_ca_ready(ANTENNA_INPUT_INFO *info)
  23. {
  24. if (ca_debug != 0)
  25. printk("%s: CaMmi=%d, CaInit=%d, CaError=%d, CaDvb=%d, "
  26. "CaModule=%d, CaAppInfo=%d, CaDateTime=%d, "
  27. "CaPmt=%d\n", __func__, info->CaMmi,
  28. info->CaInitializationStatus, info->CaErrorFlag,
  29. info->CaDvbFlag, info->CaModulePresentStatus,
  30. info->CaApplicationInfo,
  31. info->CaDateTimeRequest, info->CaPmtReply);
  32. return info->CaInitializationStatus == 1 &&
  33. info->CaErrorFlag == 0 &&
  34. info->CaDvbFlag == 1 &&
  35. info->CaModulePresentStatus == 1;
  36. }
  37. static int firesat_get_ca_flags(ANTENNA_INPUT_INFO *info)
  38. {
  39. int flags = 0;
  40. if (info->CaModulePresentStatus == 1)
  41. flags |= CA_CI_MODULE_PRESENT;
  42. if (info->CaInitializationStatus == 1 &&
  43. info->CaErrorFlag == 0 &&
  44. info->CaDvbFlag == 1)
  45. flags |= CA_CI_MODULE_READY;
  46. return flags;
  47. }
  48. static int firesat_ca_reset(struct firesat *firesat)
  49. {
  50. if (ca_debug)
  51. printk(KERN_INFO "%s: ioctl CA_RESET\n", __func__);
  52. if (avc_ca_reset(firesat))
  53. return -EFAULT;
  54. return 0;
  55. }
  56. static int firesat_ca_get_caps(struct firesat *firesat, void *arg)
  57. {
  58. struct ca_caps *cap_p = (struct ca_caps*)arg;
  59. int err = 0;
  60. cap_p->slot_num = 1;
  61. cap_p->slot_type = CA_CI;
  62. cap_p->descr_num = 1;
  63. cap_p->descr_type = CA_ECD;
  64. if (ca_debug)
  65. printk(KERN_INFO "%s: ioctl CA_GET_CAP\n", __func__);
  66. return err;
  67. }
  68. static int firesat_ca_get_slot_info(struct firesat *firesat, void *arg)
  69. {
  70. ANTENNA_INPUT_INFO info;
  71. struct ca_slot_info *slot_p = (struct ca_slot_info*)arg;
  72. if (ca_debug)
  73. printk(KERN_INFO "%s: ioctl CA_GET_SLOT_INFO on slot %d.\n",
  74. __func__, slot_p->num);
  75. if (AVCTunerStatus(firesat, &info))
  76. return -EFAULT;
  77. if (slot_p->num == 0) {
  78. slot_p->type = CA_CI;
  79. slot_p->flags = firesat_get_ca_flags(&info);
  80. }
  81. else {
  82. return -EFAULT;
  83. }
  84. return 0;
  85. }
  86. static int firesat_ca_app_info(struct firesat *firesat, void *arg)
  87. {
  88. struct ca_msg *reply_p = (struct ca_msg*)arg;
  89. int i;
  90. if (avc_ca_app_info(firesat, reply_p->msg, &reply_p->length))
  91. return -EFAULT;
  92. if (ca_debug) {
  93. printk(KERN_INFO "%s: Creating TAG_APP_INFO message:",
  94. __func__);
  95. for (i = 0; i < reply_p->length; i++)
  96. printk("0x%02X, ", (unsigned char)reply_p->msg[i]);
  97. printk("\n");
  98. }
  99. return 0;
  100. }
  101. static int firesat_ca_info(struct firesat *firesat, void *arg)
  102. {
  103. struct ca_msg *reply_p = (struct ca_msg*)arg;
  104. int i;
  105. if (avc_ca_info(firesat, reply_p->msg, &reply_p->length))
  106. return -EFAULT;
  107. if (ca_debug) {
  108. printk(KERN_INFO "%s: Creating TAG_CA_INFO message:",
  109. __func__);
  110. for (i = 0; i < reply_p->length; i++)
  111. printk("0x%02X, ", (unsigned char)reply_p->msg[i]);
  112. printk("\n");
  113. }
  114. return 0;
  115. }
  116. static int firesat_ca_get_mmi(struct firesat *firesat, void *arg)
  117. {
  118. struct ca_msg *reply_p = (struct ca_msg*)arg;
  119. int i;
  120. if (avc_ca_get_mmi(firesat, reply_p->msg, &reply_p->length))
  121. return -EFAULT;
  122. if (ca_debug) {
  123. printk(KERN_INFO "%s: Creating MMI reply INFO message:",
  124. __func__);
  125. for (i = 0; i < reply_p->length; i++)
  126. printk("0x%02X, ", (unsigned char)reply_p->msg[i]);
  127. printk("\n");
  128. }
  129. return 0;
  130. }
  131. static int firesat_ca_get_msg(struct firesat *firesat, void *arg)
  132. {
  133. int err;
  134. ANTENNA_INPUT_INFO info;
  135. switch (firesat->ca_last_command) {
  136. case TAG_APP_INFO_ENQUIRY:
  137. err = firesat_ca_app_info(firesat, arg);
  138. break;
  139. case TAG_CA_INFO_ENQUIRY:
  140. err = firesat_ca_info(firesat, arg);
  141. break;
  142. default:
  143. if (AVCTunerStatus(firesat, &info))
  144. err = -EFAULT;
  145. else if (info.CaMmi == 1) {
  146. err = firesat_ca_get_mmi(firesat, arg);
  147. }
  148. else {
  149. printk(KERN_INFO "%s: Unhandled message 0x%08X\n",
  150. __func__, firesat->ca_last_command);
  151. err = -EFAULT;
  152. }
  153. }
  154. firesat->ca_last_command = 0;
  155. return err;
  156. }
  157. static int firesat_ca_pmt(struct firesat *firesat, void *arg)
  158. {
  159. struct ca_msg *msg_p = (struct ca_msg*)arg;
  160. int data_pos;
  161. if (msg_p->msg[3] & 0x80)
  162. data_pos = (msg_p->msg[4] && 0x7F) + 4;
  163. else
  164. data_pos = 4;
  165. if (avc_ca_pmt(firesat, &msg_p->msg[data_pos],
  166. msg_p->length - data_pos))
  167. return -EFAULT;
  168. return 0;
  169. }
  170. static int firesat_ca_send_msg(struct firesat *firesat, void *arg)
  171. {
  172. int err;
  173. struct ca_msg *msg_p = (struct ca_msg*)arg;
  174. // Do we need a semaphore for this?
  175. firesat->ca_last_command =
  176. (msg_p->msg[0] << 16) + (msg_p->msg[1] << 8) + msg_p->msg[2];
  177. switch (firesat->ca_last_command) {
  178. case TAG_CA_PMT:
  179. if (ca_debug != 0)
  180. printk(KERN_INFO "%s: Message received: TAG_CA_PMT\n",
  181. __func__);
  182. err = firesat_ca_pmt(firesat, arg);
  183. break;
  184. case TAG_APP_INFO_ENQUIRY:
  185. // This is all handled in ca_get_msg
  186. if (ca_debug != 0)
  187. printk(KERN_INFO "%s: Message received: "
  188. "TAG_APP_INFO_ENQUIRY\n", __func__);
  189. err = 0;
  190. break;
  191. case TAG_CA_INFO_ENQUIRY:
  192. // This is all handled in ca_get_msg
  193. if (ca_debug != 0)
  194. printk(KERN_INFO "%s: Message received: "
  195. "TAG_CA_APP_INFO_ENQUIRY\n", __func__);
  196. err = 0;
  197. break;
  198. case TAG_ENTER_MENU:
  199. if (ca_debug != 0)
  200. printk(KERN_INFO "%s: Entering CA menu.\n", __func__);
  201. err = avc_ca_enter_menu(firesat);
  202. break;
  203. default:
  204. printk(KERN_ERR "%s: Unhandled unknown message 0x%08X\n",
  205. __func__, firesat->ca_last_command);
  206. err = -EFAULT;
  207. }
  208. return err;
  209. }
  210. static int firesat_ca_ioctl(struct inode *inode, struct file *file,
  211. unsigned int cmd, void *arg)
  212. {
  213. struct dvb_device* dvbdev = (struct dvb_device*) file->private_data;
  214. struct firesat *firesat = dvbdev->priv;
  215. int err;
  216. ANTENNA_INPUT_INFO info;
  217. switch(cmd) {
  218. case CA_RESET:
  219. err = firesat_ca_reset(firesat);
  220. break;
  221. case CA_GET_CAP:
  222. err = firesat_ca_get_caps(firesat, arg);
  223. break;
  224. case CA_GET_SLOT_INFO:
  225. err = firesat_ca_get_slot_info(firesat, arg);
  226. break;
  227. case CA_GET_MSG:
  228. err = firesat_ca_get_msg(firesat, arg);
  229. break;
  230. case CA_SEND_MSG:
  231. err = firesat_ca_send_msg(firesat, arg);
  232. break;
  233. default:
  234. printk(KERN_INFO "%s: Unhandled ioctl, command: %u\n",__func__,
  235. cmd);
  236. err = -EOPNOTSUPP;
  237. }
  238. if (AVCTunerStatus(firesat, &info))
  239. return err;
  240. firesat_ca_ready(&info);
  241. return err;
  242. }
  243. static int firesat_get_date_time_request(struct firesat *firesat)
  244. {
  245. if (ca_debug)
  246. printk(KERN_INFO "%s: Retrieving Time/Date request\n",
  247. __func__);
  248. if (avc_ca_get_time_date(firesat, &firesat->ca_time_interval))
  249. return -EFAULT;
  250. if (ca_debug)
  251. printk(KERN_INFO "%s: Time/Date interval is %d\n",
  252. __func__, firesat->ca_time_interval);
  253. return 0;
  254. }
  255. static int firesat_ca_io_open(struct inode *inode, struct file *file)
  256. {
  257. if (ca_debug != 0)
  258. printk(KERN_INFO "%s\n",__func__);
  259. return dvb_generic_open(inode, file);
  260. }
  261. static int firesat_ca_io_release(struct inode *inode, struct file *file)
  262. {
  263. if (ca_debug != 0)
  264. printk(KERN_INFO "%s\n",__func__);
  265. return dvb_generic_release(inode, file);
  266. }
  267. static unsigned int firesat_ca_io_poll(struct file *file, poll_table *wait)
  268. {
  269. if (ca_debug != 0)
  270. printk(KERN_INFO "%s\n",__func__);
  271. return POLLIN;
  272. }
  273. static struct file_operations firesat_ca_fops = {
  274. .owner = THIS_MODULE,
  275. .read = NULL, // There is no low level read anymore
  276. .write = NULL, // There is no low level write anymore
  277. .ioctl = dvb_generic_ioctl,
  278. .open = firesat_ca_io_open,
  279. .release = firesat_ca_io_release,
  280. .poll = firesat_ca_io_poll,
  281. };
  282. static struct dvb_device firesat_ca = {
  283. .priv = NULL,
  284. .users = 1,
  285. .readers = 1,
  286. .writers = 1,
  287. .fops = &firesat_ca_fops,
  288. .kernel_ioctl = firesat_ca_ioctl,
  289. };
  290. int firesat_ca_init(struct firesat *firesat)
  291. {
  292. int err;
  293. ANTENNA_INPUT_INFO info;
  294. if (AVCTunerStatus(firesat, &info))
  295. return -EINVAL;
  296. if (firesat_ca_ready(&info)) {
  297. err = dvb_register_device(firesat->adapter,
  298. &firesat->cadev,
  299. &firesat_ca, firesat,
  300. DVB_DEVICE_CA);
  301. if (info.CaApplicationInfo == 0)
  302. printk(KERN_ERR "%s: CaApplicationInfo is not set.\n",
  303. __func__);
  304. if (info.CaDateTimeRequest == 1)
  305. firesat_get_date_time_request(firesat);
  306. }
  307. else
  308. err = -EFAULT;
  309. return err;
  310. }
  311. void firesat_ca_release(struct firesat *firesat)
  312. {
  313. if (firesat->cadev)
  314. dvb_unregister_device(firesat->cadev);
  315. }