ff-stream.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /*
  2. * ff-stream.c - a part of driver for RME Fireface series
  3. *
  4. * Copyright (c) 2015-2017 Takashi Sakamoto
  5. *
  6. * Licensed under the terms of the GNU General Public License, version 2.
  7. */
  8. #include "ff.h"
  9. #define CALLBACK_TIMEOUT_MS 200
  10. static int get_rate_mode(unsigned int rate, unsigned int *mode)
  11. {
  12. int i;
  13. for (i = 0; i < CIP_SFC_COUNT; i++) {
  14. if (amdtp_rate_table[i] == rate)
  15. break;
  16. }
  17. if (i == CIP_SFC_COUNT)
  18. return -EINVAL;
  19. *mode = ((int)i - 1) / 2;
  20. return 0;
  21. }
  22. /*
  23. * Fireface 400 manages isochronous channel number in 3 bit field. Therefore,
  24. * we can allocate between 0 and 7 channel.
  25. */
  26. static int keep_resources(struct snd_ff *ff, unsigned int rate)
  27. {
  28. int mode;
  29. int err;
  30. err = get_rate_mode(rate, &mode);
  31. if (err < 0)
  32. return err;
  33. /* Keep resources for in-stream. */
  34. err = amdtp_ff_set_parameters(&ff->tx_stream, rate,
  35. ff->spec->pcm_capture_channels[mode]);
  36. if (err < 0)
  37. return err;
  38. ff->tx_resources.channels_mask = 0x00000000000000ffuLL;
  39. err = fw_iso_resources_allocate(&ff->tx_resources,
  40. amdtp_stream_get_max_payload(&ff->tx_stream),
  41. fw_parent_device(ff->unit)->max_speed);
  42. if (err < 0)
  43. return err;
  44. /* Keep resources for out-stream. */
  45. err = amdtp_ff_set_parameters(&ff->rx_stream, rate,
  46. ff->spec->pcm_playback_channels[mode]);
  47. if (err < 0)
  48. return err;
  49. ff->rx_resources.channels_mask = 0x00000000000000ffuLL;
  50. err = fw_iso_resources_allocate(&ff->rx_resources,
  51. amdtp_stream_get_max_payload(&ff->rx_stream),
  52. fw_parent_device(ff->unit)->max_speed);
  53. if (err < 0)
  54. fw_iso_resources_free(&ff->tx_resources);
  55. return err;
  56. }
  57. static void release_resources(struct snd_ff *ff)
  58. {
  59. fw_iso_resources_free(&ff->tx_resources);
  60. fw_iso_resources_free(&ff->rx_resources);
  61. }
  62. static inline void finish_session(struct snd_ff *ff)
  63. {
  64. ff->spec->protocol->finish_session(ff);
  65. ff->spec->protocol->switch_fetching_mode(ff, false);
  66. }
  67. static int init_stream(struct snd_ff *ff, enum amdtp_stream_direction dir)
  68. {
  69. int err;
  70. struct fw_iso_resources *resources;
  71. struct amdtp_stream *stream;
  72. if (dir == AMDTP_IN_STREAM) {
  73. resources = &ff->tx_resources;
  74. stream = &ff->tx_stream;
  75. } else {
  76. resources = &ff->rx_resources;
  77. stream = &ff->rx_stream;
  78. }
  79. err = fw_iso_resources_init(resources, ff->unit);
  80. if (err < 0)
  81. return err;
  82. err = amdtp_ff_init(stream, ff->unit, dir);
  83. if (err < 0)
  84. fw_iso_resources_destroy(resources);
  85. return err;
  86. }
  87. static void destroy_stream(struct snd_ff *ff, enum amdtp_stream_direction dir)
  88. {
  89. if (dir == AMDTP_IN_STREAM) {
  90. amdtp_stream_destroy(&ff->tx_stream);
  91. fw_iso_resources_destroy(&ff->tx_resources);
  92. } else {
  93. amdtp_stream_destroy(&ff->rx_stream);
  94. fw_iso_resources_destroy(&ff->rx_resources);
  95. }
  96. }
  97. int snd_ff_stream_init_duplex(struct snd_ff *ff)
  98. {
  99. int err;
  100. err = init_stream(ff, AMDTP_OUT_STREAM);
  101. if (err < 0)
  102. goto end;
  103. err = init_stream(ff, AMDTP_IN_STREAM);
  104. if (err < 0)
  105. destroy_stream(ff, AMDTP_OUT_STREAM);
  106. end:
  107. return err;
  108. }
  109. /*
  110. * This function should be called before starting streams or after stopping
  111. * streams.
  112. */
  113. void snd_ff_stream_destroy_duplex(struct snd_ff *ff)
  114. {
  115. destroy_stream(ff, AMDTP_IN_STREAM);
  116. destroy_stream(ff, AMDTP_OUT_STREAM);
  117. }
  118. int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
  119. {
  120. unsigned int curr_rate;
  121. enum snd_ff_clock_src src;
  122. int err;
  123. if (ff->substreams_counter == 0)
  124. return 0;
  125. err = ff->spec->protocol->get_clock(ff, &curr_rate, &src);
  126. if (err < 0)
  127. return err;
  128. if (curr_rate != rate ||
  129. amdtp_streaming_error(&ff->tx_stream) ||
  130. amdtp_streaming_error(&ff->rx_stream)) {
  131. finish_session(ff);
  132. amdtp_stream_stop(&ff->tx_stream);
  133. amdtp_stream_stop(&ff->rx_stream);
  134. release_resources(ff);
  135. }
  136. /*
  137. * Regardless of current source of clock signal, drivers transfer some
  138. * packets. Then, the device transfers packets.
  139. */
  140. if (!amdtp_stream_running(&ff->rx_stream)) {
  141. err = keep_resources(ff, rate);
  142. if (err < 0)
  143. goto error;
  144. err = ff->spec->protocol->begin_session(ff, rate);
  145. if (err < 0)
  146. goto error;
  147. err = amdtp_stream_start(&ff->rx_stream,
  148. ff->rx_resources.channel,
  149. fw_parent_device(ff->unit)->max_speed);
  150. if (err < 0)
  151. goto error;
  152. if (!amdtp_stream_wait_callback(&ff->rx_stream,
  153. CALLBACK_TIMEOUT_MS)) {
  154. err = -ETIMEDOUT;
  155. goto error;
  156. }
  157. err = ff->spec->protocol->switch_fetching_mode(ff, true);
  158. if (err < 0)
  159. goto error;
  160. }
  161. if (!amdtp_stream_running(&ff->tx_stream)) {
  162. err = amdtp_stream_start(&ff->tx_stream,
  163. ff->tx_resources.channel,
  164. fw_parent_device(ff->unit)->max_speed);
  165. if (err < 0)
  166. goto error;
  167. if (!amdtp_stream_wait_callback(&ff->tx_stream,
  168. CALLBACK_TIMEOUT_MS)) {
  169. err = -ETIMEDOUT;
  170. goto error;
  171. }
  172. }
  173. return 0;
  174. error:
  175. amdtp_stream_stop(&ff->tx_stream);
  176. amdtp_stream_stop(&ff->rx_stream);
  177. finish_session(ff);
  178. release_resources(ff);
  179. return err;
  180. }
  181. void snd_ff_stream_stop_duplex(struct snd_ff *ff)
  182. {
  183. if (ff->substreams_counter > 0)
  184. return;
  185. amdtp_stream_stop(&ff->tx_stream);
  186. amdtp_stream_stop(&ff->rx_stream);
  187. finish_session(ff);
  188. release_resources(ff);
  189. }
  190. void snd_ff_stream_update_duplex(struct snd_ff *ff)
  191. {
  192. /* The device discontinue to transfer packets. */
  193. amdtp_stream_pcm_abort(&ff->tx_stream);
  194. amdtp_stream_stop(&ff->tx_stream);
  195. amdtp_stream_pcm_abort(&ff->rx_stream);
  196. amdtp_stream_stop(&ff->rx_stream);
  197. fw_iso_resources_update(&ff->tx_resources);
  198. fw_iso_resources_update(&ff->rx_resources);
  199. }
  200. void snd_ff_stream_lock_changed(struct snd_ff *ff)
  201. {
  202. ff->dev_lock_changed = true;
  203. wake_up(&ff->hwdep_wait);
  204. }
  205. int snd_ff_stream_lock_try(struct snd_ff *ff)
  206. {
  207. int err;
  208. spin_lock_irq(&ff->lock);
  209. /* user land lock this */
  210. if (ff->dev_lock_count < 0) {
  211. err = -EBUSY;
  212. goto end;
  213. }
  214. /* this is the first time */
  215. if (ff->dev_lock_count++ == 0)
  216. snd_ff_stream_lock_changed(ff);
  217. err = 0;
  218. end:
  219. spin_unlock_irq(&ff->lock);
  220. return err;
  221. }
  222. void snd_ff_stream_lock_release(struct snd_ff *ff)
  223. {
  224. spin_lock_irq(&ff->lock);
  225. if (WARN_ON(ff->dev_lock_count <= 0))
  226. goto end;
  227. if (--ff->dev_lock_count == 0)
  228. snd_ff_stream_lock_changed(ff);
  229. end:
  230. spin_unlock_irq(&ff->lock);
  231. }