firesat_dvb.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  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/errno.h>
  13. #include <linux/kernel.h>
  14. #include <linux/mutex.h>
  15. #include <linux/types.h>
  16. #include <dvb_demux.h>
  17. #include <dvb_frontend.h>
  18. #include <dvbdev.h>
  19. #include "avc_api.h"
  20. #include "firesat.h"
  21. #include "firesat-ci.h"
  22. DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
  23. static struct firesat_channel *firesat_channel_allocate(struct firesat *firesat)
  24. {
  25. struct firesat_channel *c = NULL;
  26. int k;
  27. if (mutex_lock_interruptible(&firesat->demux_mutex))
  28. return NULL;
  29. for (k = 0; k < 16; k++)
  30. if (!firesat->channel[k].active) {
  31. firesat->channel[k].active = true;
  32. c = &firesat->channel[k];
  33. break;
  34. }
  35. mutex_unlock(&firesat->demux_mutex);
  36. return c;
  37. }
  38. static int firesat_channel_collect(struct firesat *firesat, int *pidc, u16 pid[])
  39. {
  40. int k, l = 0;
  41. if (mutex_lock_interruptible(&firesat->demux_mutex))
  42. return -EINTR;
  43. for (k = 0; k < 16; k++)
  44. if (firesat->channel[k].active)
  45. pid[l++] = firesat->channel[k].pid;
  46. mutex_unlock(&firesat->demux_mutex);
  47. *pidc = l;
  48. return 0;
  49. }
  50. static int firesat_channel_release(struct firesat *firesat,
  51. struct firesat_channel *channel)
  52. {
  53. if (mutex_lock_interruptible(&firesat->demux_mutex))
  54. return -EINTR;
  55. channel->active = false;
  56. mutex_unlock(&firesat->demux_mutex);
  57. return 0;
  58. }
  59. int firesat_start_feed(struct dvb_demux_feed *dvbdmxfeed)
  60. {
  61. struct firesat *firesat = (struct firesat*)dvbdmxfeed->demux->priv;
  62. struct firesat_channel *channel;
  63. int pidc,k;
  64. u16 pids[16];
  65. switch (dvbdmxfeed->type) {
  66. case DMX_TYPE_TS:
  67. case DMX_TYPE_SEC:
  68. break;
  69. default:
  70. printk(KERN_ERR "%s: invalid type %u\n",
  71. __func__, dvbdmxfeed->type);
  72. return -EINVAL;
  73. }
  74. if (dvbdmxfeed->type == DMX_TYPE_TS) {
  75. switch (dvbdmxfeed->pes_type) {
  76. case DMX_TS_PES_VIDEO:
  77. case DMX_TS_PES_AUDIO:
  78. case DMX_TS_PES_TELETEXT:
  79. case DMX_TS_PES_PCR:
  80. case DMX_TS_PES_OTHER:
  81. //Dirty fix to keep firesat->channel pid-list up to date
  82. for(k=0;k<16;k++){
  83. if (!firesat->channel[k].active)
  84. firesat->channel[k].pid =
  85. dvbdmxfeed->pid;
  86. break;
  87. }
  88. channel = firesat_channel_allocate(firesat);
  89. break;
  90. default:
  91. printk(KERN_ERR "%s: invalid pes type %u\n",
  92. __func__, dvbdmxfeed->pes_type);
  93. return -EINVAL;
  94. }
  95. } else {
  96. channel = firesat_channel_allocate(firesat);
  97. }
  98. if (!channel) {
  99. printk(KERN_ERR "%s: busy!\n", __func__);
  100. return -EBUSY;
  101. }
  102. dvbdmxfeed->priv = channel;
  103. channel->pid = dvbdmxfeed->pid;
  104. if (firesat_channel_collect(firesat, &pidc, pids)) {
  105. firesat_channel_release(firesat, channel);
  106. printk(KERN_ERR "%s: could not collect pids!\n", __func__);
  107. return -EINTR;
  108. }
  109. if (dvbdmxfeed->pid == 8192) {
  110. k = avc_tuner_get_ts(firesat);
  111. if (k) {
  112. firesat_channel_release(firesat, channel);
  113. printk("%s: AVCTuner_GetTS failed with error %d\n",
  114. __func__, k);
  115. return k;
  116. }
  117. } else {
  118. k = avc_tuner_set_pids(firesat, pidc, pids);
  119. if (k) {
  120. firesat_channel_release(firesat, channel);
  121. printk("%s: AVCTuner_SetPIDs failed with error %d\n",
  122. __func__, k);
  123. return k;
  124. }
  125. }
  126. return 0;
  127. }
  128. int firesat_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
  129. {
  130. struct dvb_demux *demux = dvbdmxfeed->demux;
  131. struct firesat *firesat = (struct firesat*)demux->priv;
  132. struct firesat_channel *c = dvbdmxfeed->priv;
  133. int k, l;
  134. u16 pids[16];
  135. if (dvbdmxfeed->type == DMX_TYPE_TS && !((dvbdmxfeed->ts_type & TS_PACKET) &&
  136. (demux->dmx.frontend->source != DMX_MEMORY_FE))) {
  137. if (dvbdmxfeed->ts_type & TS_DECODER) {
  138. if (dvbdmxfeed->pes_type >= DMX_TS_PES_OTHER ||
  139. !demux->pesfilter[dvbdmxfeed->pes_type])
  140. return -EINVAL;
  141. demux->pids[dvbdmxfeed->pes_type] |= 0x8000;
  142. demux->pesfilter[dvbdmxfeed->pes_type] = NULL;
  143. }
  144. if (!(dvbdmxfeed->ts_type & TS_DECODER &&
  145. dvbdmxfeed->pes_type < DMX_TS_PES_OTHER))
  146. return 0;
  147. }
  148. if (mutex_lock_interruptible(&firesat->demux_mutex))
  149. return -EINTR;
  150. /* list except channel to be removed */
  151. for (k = 0, l = 0; k < 16; k++)
  152. if (firesat->channel[k].active) {
  153. if (&firesat->channel[k] != c)
  154. pids[l++] = firesat->channel[k].pid;
  155. else
  156. firesat->channel[k].active = false;
  157. }
  158. k = avc_tuner_set_pids(firesat, l, pids);
  159. if (!k)
  160. c->active = false;
  161. mutex_unlock(&firesat->demux_mutex);
  162. return k;
  163. }
  164. int firesat_dvbdev_init(struct firesat *firesat, struct device *dev)
  165. {
  166. int err;
  167. err = DVB_REGISTER_ADAPTER(&firesat->adapter,
  168. firedtv_model_names[firesat->type],
  169. THIS_MODULE, dev, adapter_nr);
  170. if (err)
  171. goto fail_log;
  172. /*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/
  173. firesat->demux.dmx.capabilities = 0;
  174. firesat->demux.priv = (void *)firesat;
  175. firesat->demux.filternum = 16;
  176. firesat->demux.feednum = 16;
  177. firesat->demux.start_feed = firesat_start_feed;
  178. firesat->demux.stop_feed = firesat_stop_feed;
  179. firesat->demux.write_to_decoder = NULL;
  180. err = dvb_dmx_init(&firesat->demux);
  181. if (err)
  182. goto fail_unreg_adapter;
  183. firesat->dmxdev.filternum = 16;
  184. firesat->dmxdev.demux = &firesat->demux.dmx;
  185. firesat->dmxdev.capabilities = 0;
  186. err = dvb_dmxdev_init(&firesat->dmxdev, &firesat->adapter);
  187. if (err)
  188. goto fail_dmx_release;
  189. firesat->frontend.source = DMX_FRONTEND_0;
  190. err = firesat->demux.dmx.add_frontend(&firesat->demux.dmx,
  191. &firesat->frontend);
  192. if (err)
  193. goto fail_dmxdev_release;
  194. err = firesat->demux.dmx.connect_frontend(&firesat->demux.dmx,
  195. &firesat->frontend);
  196. if (err)
  197. goto fail_rem_frontend;
  198. dvb_net_init(&firesat->adapter, &firesat->dvbnet, &firesat->demux.dmx);
  199. firesat_frontend_init(firesat);
  200. err = dvb_register_frontend(&firesat->adapter, &firesat->fe);
  201. if (err)
  202. goto fail_net_release;
  203. err = firesat_ca_register(firesat);
  204. if (err)
  205. dev_info(dev, "Conditional Access Module not enabled\n");
  206. return 0;
  207. fail_net_release:
  208. dvb_net_release(&firesat->dvbnet);
  209. firesat->demux.dmx.close(&firesat->demux.dmx);
  210. fail_rem_frontend:
  211. firesat->demux.dmx.remove_frontend(&firesat->demux.dmx,
  212. &firesat->frontend);
  213. fail_dmxdev_release:
  214. dvb_dmxdev_release(&firesat->dmxdev);
  215. fail_dmx_release:
  216. dvb_dmx_release(&firesat->demux);
  217. fail_unreg_adapter:
  218. dvb_unregister_adapter(&firesat->adapter);
  219. fail_log:
  220. dev_err(dev, "DVB initialization failed\n");
  221. return err;
  222. }