c8sectpfe-common.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * c8sectpfe-common.c - C8SECTPFE STi DVB driver
  4. *
  5. * Copyright (c) STMicroelectronics 2015
  6. *
  7. * Author: Peter Griffin <peter.griffin@linaro.org>
  8. *
  9. */
  10. #include <linux/completion.h>
  11. #include <linux/delay.h>
  12. #include <linux/device.h>
  13. #include <linux/dvb/dmx.h>
  14. #include <linux/errno.h>
  15. #include <linux/init.h>
  16. #include <linux/interrupt.h>
  17. #include <linux/io.h>
  18. #include <linux/ioport.h>
  19. #include <linux/module.h>
  20. #include <linux/slab.h>
  21. #include <linux/time.h>
  22. #include <linux/wait.h>
  23. #include <media/dmxdev.h>
  24. #include <media/dvbdev.h>
  25. #include <media/dvb_demux.h>
  26. #include <media/dvb_frontend.h>
  27. #include <media/dvb_net.h>
  28. #include "c8sectpfe-common.h"
  29. #include "c8sectpfe-core.h"
  30. #include "c8sectpfe-dvb.h"
  31. static int register_dvb(struct stdemux *demux, struct dvb_adapter *adap,
  32. void *start_feed, void *stop_feed,
  33. struct c8sectpfei *fei)
  34. {
  35. int result;
  36. demux->dvb_demux.dmx.capabilities = DMX_TS_FILTERING |
  37. DMX_SECTION_FILTERING |
  38. DMX_MEMORY_BASED_FILTERING;
  39. demux->dvb_demux.priv = demux;
  40. demux->dvb_demux.filternum = C8SECTPFE_MAXCHANNEL;
  41. demux->dvb_demux.feednum = C8SECTPFE_MAXCHANNEL;
  42. demux->dvb_demux.start_feed = start_feed;
  43. demux->dvb_demux.stop_feed = stop_feed;
  44. demux->dvb_demux.write_to_decoder = NULL;
  45. result = dvb_dmx_init(&demux->dvb_demux);
  46. if (result < 0) {
  47. dev_err(fei->dev, "dvb_dmx_init failed (errno = %d)\n",
  48. result);
  49. goto err_dmx;
  50. }
  51. demux->dmxdev.filternum = demux->dvb_demux.filternum;
  52. demux->dmxdev.demux = &demux->dvb_demux.dmx;
  53. demux->dmxdev.capabilities = 0;
  54. result = dvb_dmxdev_init(&demux->dmxdev, adap);
  55. if (result < 0) {
  56. dev_err(fei->dev, "dvb_dmxdev_init failed (errno = %d)\n",
  57. result);
  58. goto err_dmxdev;
  59. }
  60. demux->hw_frontend.source = DMX_FRONTEND_0 + demux->tsin_index;
  61. result = demux->dvb_demux.dmx.add_frontend(&demux->dvb_demux.dmx,
  62. &demux->hw_frontend);
  63. if (result < 0) {
  64. dev_err(fei->dev, "add_frontend failed (errno = %d)\n", result);
  65. goto err_fe_hw;
  66. }
  67. demux->mem_frontend.source = DMX_MEMORY_FE;
  68. result = demux->dvb_demux.dmx.add_frontend(&demux->dvb_demux.dmx,
  69. &demux->mem_frontend);
  70. if (result < 0) {
  71. dev_err(fei->dev, "add_frontend failed (%d)\n", result);
  72. goto err_fe_mem;
  73. }
  74. result = demux->dvb_demux.dmx.connect_frontend(&demux->dvb_demux.dmx,
  75. &demux->hw_frontend);
  76. if (result < 0) {
  77. dev_err(fei->dev, "connect_frontend (%d)\n", result);
  78. goto err_fe_con;
  79. }
  80. return 0;
  81. err_fe_con:
  82. demux->dvb_demux.dmx.remove_frontend(&demux->dvb_demux.dmx,
  83. &demux->mem_frontend);
  84. err_fe_mem:
  85. demux->dvb_demux.dmx.remove_frontend(&demux->dvb_demux.dmx,
  86. &demux->hw_frontend);
  87. err_fe_hw:
  88. dvb_dmxdev_release(&demux->dmxdev);
  89. err_dmxdev:
  90. dvb_dmx_release(&demux->dvb_demux);
  91. err_dmx:
  92. return result;
  93. }
  94. static void unregister_dvb(struct stdemux *demux)
  95. {
  96. demux->dvb_demux.dmx.remove_frontend(&demux->dvb_demux.dmx,
  97. &demux->mem_frontend);
  98. demux->dvb_demux.dmx.remove_frontend(&demux->dvb_demux.dmx,
  99. &demux->hw_frontend);
  100. dvb_dmxdev_release(&demux->dmxdev);
  101. dvb_dmx_release(&demux->dvb_demux);
  102. }
  103. static struct c8sectpfe *c8sectpfe_create(struct c8sectpfei *fei,
  104. void *start_feed,
  105. void *stop_feed)
  106. {
  107. struct c8sectpfe *c8sectpfe;
  108. int result;
  109. int i, j;
  110. short int ids[] = { -1 };
  111. c8sectpfe = kzalloc(sizeof(struct c8sectpfe), GFP_KERNEL);
  112. if (!c8sectpfe)
  113. goto err1;
  114. mutex_init(&c8sectpfe->lock);
  115. c8sectpfe->device = fei->dev;
  116. result = dvb_register_adapter(&c8sectpfe->adapter, "STi c8sectpfe",
  117. THIS_MODULE, fei->dev, ids);
  118. if (result < 0) {
  119. dev_err(fei->dev, "dvb_register_adapter failed (errno = %d)\n",
  120. result);
  121. goto err2;
  122. }
  123. c8sectpfe->adapter.priv = fei;
  124. for (i = 0; i < fei->tsin_count; i++) {
  125. c8sectpfe->demux[i].tsin_index = i;
  126. c8sectpfe->demux[i].c8sectpfei = fei;
  127. result = register_dvb(&c8sectpfe->demux[i], &c8sectpfe->adapter,
  128. start_feed, stop_feed, fei);
  129. if (result < 0) {
  130. dev_err(fei->dev,
  131. "register_dvb feed=%d failed (errno = %d)\n",
  132. result, i);
  133. /* we take a all or nothing approach */
  134. for (j = 0; j < i; j++)
  135. unregister_dvb(&c8sectpfe->demux[j]);
  136. goto err3;
  137. }
  138. }
  139. c8sectpfe->num_feeds = fei->tsin_count;
  140. return c8sectpfe;
  141. err3:
  142. dvb_unregister_adapter(&c8sectpfe->adapter);
  143. err2:
  144. kfree(c8sectpfe);
  145. err1:
  146. return NULL;
  147. };
  148. static void c8sectpfe_delete(struct c8sectpfe *c8sectpfe)
  149. {
  150. int i;
  151. if (!c8sectpfe)
  152. return;
  153. for (i = 0; i < c8sectpfe->num_feeds; i++)
  154. unregister_dvb(&c8sectpfe->demux[i]);
  155. dvb_unregister_adapter(&c8sectpfe->adapter);
  156. kfree(c8sectpfe);
  157. };
  158. void c8sectpfe_tuner_unregister_frontend(struct c8sectpfe *c8sectpfe,
  159. struct c8sectpfei *fei)
  160. {
  161. int n;
  162. struct channel_info *tsin;
  163. for (n = 0; n < fei->tsin_count; n++) {
  164. tsin = fei->channel_data[n];
  165. if (tsin) {
  166. if (tsin->frontend) {
  167. dvb_unregister_frontend(tsin->frontend);
  168. dvb_frontend_detach(tsin->frontend);
  169. }
  170. i2c_put_adapter(tsin->i2c_adapter);
  171. if (tsin->i2c_client) {
  172. module_put(tsin->i2c_client->dev.driver->owner);
  173. i2c_unregister_device(tsin->i2c_client);
  174. }
  175. }
  176. }
  177. c8sectpfe_delete(c8sectpfe);
  178. };
  179. int c8sectpfe_tuner_register_frontend(struct c8sectpfe **c8sectpfe,
  180. struct c8sectpfei *fei,
  181. void *start_feed,
  182. void *stop_feed)
  183. {
  184. struct channel_info *tsin;
  185. struct dvb_frontend *frontend;
  186. int n, res;
  187. *c8sectpfe = c8sectpfe_create(fei, start_feed, stop_feed);
  188. if (!*c8sectpfe)
  189. return -ENOMEM;
  190. for (n = 0; n < fei->tsin_count; n++) {
  191. tsin = fei->channel_data[n];
  192. res = c8sectpfe_frontend_attach(&frontend, *c8sectpfe, tsin, n);
  193. if (res)
  194. goto err;
  195. res = dvb_register_frontend(&c8sectpfe[0]->adapter, frontend);
  196. if (res < 0) {
  197. dev_err(fei->dev, "dvb_register_frontend failed (%d)\n",
  198. res);
  199. goto err;
  200. }
  201. tsin->frontend = frontend;
  202. }
  203. return 0;
  204. err:
  205. c8sectpfe_tuner_unregister_frontend(*c8sectpfe, fei);
  206. return res;
  207. }