digi00x-pcm.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. /*
  2. * digi00x-pcm.c - a part of driver for Digidesign Digi 002/003 family
  3. *
  4. * Copyright (c) 2014-2015 Takashi Sakamoto
  5. *
  6. * Licensed under the terms of the GNU General Public License, version 2.
  7. */
  8. #include "digi00x.h"
  9. static int hw_rule_rate(struct snd_pcm_hw_params *params,
  10. struct snd_pcm_hw_rule *rule)
  11. {
  12. struct snd_interval *r =
  13. hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
  14. const struct snd_interval *c =
  15. hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
  16. struct snd_interval t = {
  17. .min = UINT_MAX, .max = 0, .integer = 1,
  18. };
  19. unsigned int i;
  20. for (i = 0; i < SND_DG00X_RATE_COUNT; i++) {
  21. if (!snd_interval_test(c,
  22. snd_dg00x_stream_pcm_channels[i]))
  23. continue;
  24. t.min = min(t.min, snd_dg00x_stream_rates[i]);
  25. t.max = max(t.max, snd_dg00x_stream_rates[i]);
  26. }
  27. return snd_interval_refine(r, &t);
  28. }
  29. static int hw_rule_channels(struct snd_pcm_hw_params *params,
  30. struct snd_pcm_hw_rule *rule)
  31. {
  32. struct snd_interval *c =
  33. hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
  34. const struct snd_interval *r =
  35. hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
  36. struct snd_interval t = {
  37. .min = UINT_MAX, .max = 0, .integer = 1,
  38. };
  39. unsigned int i;
  40. for (i = 0; i < SND_DG00X_RATE_COUNT; i++) {
  41. if (!snd_interval_test(r, snd_dg00x_stream_rates[i]))
  42. continue;
  43. t.min = min(t.min, snd_dg00x_stream_pcm_channels[i]);
  44. t.max = max(t.max, snd_dg00x_stream_pcm_channels[i]);
  45. }
  46. return snd_interval_refine(c, &t);
  47. }
  48. static int pcm_init_hw_params(struct snd_dg00x *dg00x,
  49. struct snd_pcm_substream *substream)
  50. {
  51. struct snd_pcm_runtime *runtime = substream->runtime;
  52. struct snd_pcm_hardware *hw = &runtime->hw;
  53. struct amdtp_stream *s;
  54. int err;
  55. if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
  56. substream->runtime->hw.formats = SNDRV_PCM_FMTBIT_S32;
  57. s = &dg00x->tx_stream;
  58. } else {
  59. substream->runtime->hw.formats = SNDRV_PCM_FMTBIT_S32;
  60. s = &dg00x->rx_stream;
  61. }
  62. hw->channels_min = 10;
  63. hw->channels_max = 18;
  64. hw->rates = SNDRV_PCM_RATE_44100 |
  65. SNDRV_PCM_RATE_48000 |
  66. SNDRV_PCM_RATE_88200 |
  67. SNDRV_PCM_RATE_96000;
  68. snd_pcm_limit_hw_rates(runtime);
  69. err = snd_pcm_hw_rule_add(substream->runtime, 0,
  70. SNDRV_PCM_HW_PARAM_CHANNELS,
  71. hw_rule_channels, NULL,
  72. SNDRV_PCM_HW_PARAM_RATE, -1);
  73. if (err < 0)
  74. return err;
  75. err = snd_pcm_hw_rule_add(substream->runtime, 0,
  76. SNDRV_PCM_HW_PARAM_RATE,
  77. hw_rule_rate, NULL,
  78. SNDRV_PCM_HW_PARAM_CHANNELS, -1);
  79. if (err < 0)
  80. return err;
  81. return amdtp_dot_add_pcm_hw_constraints(s, substream->runtime);
  82. }
  83. static int pcm_open(struct snd_pcm_substream *substream)
  84. {
  85. struct snd_dg00x *dg00x = substream->private_data;
  86. enum snd_dg00x_clock clock;
  87. bool detect;
  88. unsigned int rate;
  89. int err;
  90. err = snd_dg00x_stream_lock_try(dg00x);
  91. if (err < 0)
  92. goto end;
  93. err = pcm_init_hw_params(dg00x, substream);
  94. if (err < 0)
  95. goto err_locked;
  96. /* Check current clock source. */
  97. err = snd_dg00x_stream_get_clock(dg00x, &clock);
  98. if (err < 0)
  99. goto err_locked;
  100. if (clock != SND_DG00X_CLOCK_INTERNAL) {
  101. err = snd_dg00x_stream_check_external_clock(dg00x, &detect);
  102. if (err < 0)
  103. goto err_locked;
  104. if (!detect) {
  105. err = -EBUSY;
  106. goto err_locked;
  107. }
  108. }
  109. if ((clock != SND_DG00X_CLOCK_INTERNAL) ||
  110. amdtp_stream_pcm_running(&dg00x->rx_stream) ||
  111. amdtp_stream_pcm_running(&dg00x->tx_stream)) {
  112. err = snd_dg00x_stream_get_external_rate(dg00x, &rate);
  113. if (err < 0)
  114. goto err_locked;
  115. substream->runtime->hw.rate_min = rate;
  116. substream->runtime->hw.rate_max = rate;
  117. }
  118. snd_pcm_set_sync(substream);
  119. end:
  120. return err;
  121. err_locked:
  122. snd_dg00x_stream_lock_release(dg00x);
  123. return err;
  124. }
  125. static int pcm_close(struct snd_pcm_substream *substream)
  126. {
  127. struct snd_dg00x *dg00x = substream->private_data;
  128. snd_dg00x_stream_lock_release(dg00x);
  129. return 0;
  130. }
  131. static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
  132. struct snd_pcm_hw_params *hw_params)
  133. {
  134. struct snd_dg00x *dg00x = substream->private_data;
  135. int err;
  136. err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
  137. params_buffer_bytes(hw_params));
  138. if (err < 0)
  139. return err;
  140. if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
  141. mutex_lock(&dg00x->mutex);
  142. dg00x->substreams_counter++;
  143. mutex_unlock(&dg00x->mutex);
  144. }
  145. return 0;
  146. }
  147. static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
  148. struct snd_pcm_hw_params *hw_params)
  149. {
  150. struct snd_dg00x *dg00x = substream->private_data;
  151. int err;
  152. err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
  153. params_buffer_bytes(hw_params));
  154. if (err < 0)
  155. return err;
  156. if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
  157. mutex_lock(&dg00x->mutex);
  158. dg00x->substreams_counter++;
  159. mutex_unlock(&dg00x->mutex);
  160. }
  161. return 0;
  162. }
  163. static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
  164. {
  165. struct snd_dg00x *dg00x = substream->private_data;
  166. mutex_lock(&dg00x->mutex);
  167. if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
  168. dg00x->substreams_counter--;
  169. snd_dg00x_stream_stop_duplex(dg00x);
  170. mutex_unlock(&dg00x->mutex);
  171. return snd_pcm_lib_free_vmalloc_buffer(substream);
  172. }
  173. static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
  174. {
  175. struct snd_dg00x *dg00x = substream->private_data;
  176. mutex_lock(&dg00x->mutex);
  177. if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
  178. dg00x->substreams_counter--;
  179. snd_dg00x_stream_stop_duplex(dg00x);
  180. mutex_unlock(&dg00x->mutex);
  181. return snd_pcm_lib_free_vmalloc_buffer(substream);
  182. }
  183. static int pcm_capture_prepare(struct snd_pcm_substream *substream)
  184. {
  185. struct snd_dg00x *dg00x = substream->private_data;
  186. struct snd_pcm_runtime *runtime = substream->runtime;
  187. int err;
  188. mutex_lock(&dg00x->mutex);
  189. err = snd_dg00x_stream_start_duplex(dg00x, runtime->rate);
  190. if (err >= 0)
  191. amdtp_stream_pcm_prepare(&dg00x->tx_stream);
  192. mutex_unlock(&dg00x->mutex);
  193. return err;
  194. }
  195. static int pcm_playback_prepare(struct snd_pcm_substream *substream)
  196. {
  197. struct snd_dg00x *dg00x = substream->private_data;
  198. struct snd_pcm_runtime *runtime = substream->runtime;
  199. int err;
  200. mutex_lock(&dg00x->mutex);
  201. err = snd_dg00x_stream_start_duplex(dg00x, runtime->rate);
  202. if (err >= 0) {
  203. amdtp_stream_pcm_prepare(&dg00x->rx_stream);
  204. amdtp_dot_reset(&dg00x->rx_stream);
  205. }
  206. mutex_unlock(&dg00x->mutex);
  207. return err;
  208. }
  209. static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
  210. {
  211. struct snd_dg00x *dg00x = substream->private_data;
  212. switch (cmd) {
  213. case SNDRV_PCM_TRIGGER_START:
  214. amdtp_stream_pcm_trigger(&dg00x->tx_stream, substream);
  215. break;
  216. case SNDRV_PCM_TRIGGER_STOP:
  217. amdtp_stream_pcm_trigger(&dg00x->tx_stream, NULL);
  218. break;
  219. default:
  220. return -EINVAL;
  221. }
  222. return 0;
  223. }
  224. static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
  225. {
  226. struct snd_dg00x *dg00x = substream->private_data;
  227. switch (cmd) {
  228. case SNDRV_PCM_TRIGGER_START:
  229. amdtp_stream_pcm_trigger(&dg00x->rx_stream, substream);
  230. break;
  231. case SNDRV_PCM_TRIGGER_STOP:
  232. amdtp_stream_pcm_trigger(&dg00x->rx_stream, NULL);
  233. break;
  234. default:
  235. return -EINVAL;
  236. }
  237. return 0;
  238. }
  239. static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
  240. {
  241. struct snd_dg00x *dg00x = sbstrm->private_data;
  242. return amdtp_stream_pcm_pointer(&dg00x->tx_stream);
  243. }
  244. static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
  245. {
  246. struct snd_dg00x *dg00x = sbstrm->private_data;
  247. return amdtp_stream_pcm_pointer(&dg00x->rx_stream);
  248. }
  249. static int pcm_capture_ack(struct snd_pcm_substream *substream)
  250. {
  251. struct snd_dg00x *dg00x = substream->private_data;
  252. return amdtp_stream_pcm_ack(&dg00x->tx_stream);
  253. }
  254. static int pcm_playback_ack(struct snd_pcm_substream *substream)
  255. {
  256. struct snd_dg00x *dg00x = substream->private_data;
  257. return amdtp_stream_pcm_ack(&dg00x->rx_stream);
  258. }
  259. int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x)
  260. {
  261. static const struct snd_pcm_ops capture_ops = {
  262. .open = pcm_open,
  263. .close = pcm_close,
  264. .ioctl = snd_pcm_lib_ioctl,
  265. .hw_params = pcm_capture_hw_params,
  266. .hw_free = pcm_capture_hw_free,
  267. .prepare = pcm_capture_prepare,
  268. .trigger = pcm_capture_trigger,
  269. .pointer = pcm_capture_pointer,
  270. .ack = pcm_capture_ack,
  271. .page = snd_pcm_lib_get_vmalloc_page,
  272. };
  273. static const struct snd_pcm_ops playback_ops = {
  274. .open = pcm_open,
  275. .close = pcm_close,
  276. .ioctl = snd_pcm_lib_ioctl,
  277. .hw_params = pcm_playback_hw_params,
  278. .hw_free = pcm_playback_hw_free,
  279. .prepare = pcm_playback_prepare,
  280. .trigger = pcm_playback_trigger,
  281. .pointer = pcm_playback_pointer,
  282. .ack = pcm_playback_ack,
  283. .page = snd_pcm_lib_get_vmalloc_page,
  284. };
  285. struct snd_pcm *pcm;
  286. int err;
  287. err = snd_pcm_new(dg00x->card, dg00x->card->driver, 0, 1, 1, &pcm);
  288. if (err < 0)
  289. return err;
  290. pcm->private_data = dg00x;
  291. snprintf(pcm->name, sizeof(pcm->name),
  292. "%s PCM", dg00x->card->shortname);
  293. snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
  294. snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
  295. return 0;
  296. }