bebob_pcm.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. /*
  2. * bebob_pcm.c - a part of driver for BeBoB based devices
  3. *
  4. * Copyright (c) 2013-2014 Takashi Sakamoto
  5. *
  6. * Licensed under the terms of the GNU General Public License, version 2.
  7. */
  8. #include "./bebob.h"
  9. static int
  10. hw_rule_rate(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
  11. {
  12. struct snd_bebob_stream_formation *formations = rule->private;
  13. struct snd_interval *r =
  14. hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
  15. const struct snd_interval *c =
  16. hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
  17. struct snd_interval t = {
  18. .min = UINT_MAX, .max = 0, .integer = 1
  19. };
  20. unsigned int i;
  21. for (i = 0; i < SND_BEBOB_STRM_FMT_ENTRIES; i++) {
  22. /* entry is invalid */
  23. if (formations[i].pcm == 0)
  24. continue;
  25. if (!snd_interval_test(c, formations[i].pcm))
  26. continue;
  27. t.min = min(t.min, snd_bebob_rate_table[i]);
  28. t.max = max(t.max, snd_bebob_rate_table[i]);
  29. }
  30. return snd_interval_refine(r, &t);
  31. }
  32. static int
  33. hw_rule_channels(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
  34. {
  35. struct snd_bebob_stream_formation *formations = rule->private;
  36. struct snd_interval *c =
  37. hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
  38. const struct snd_interval *r =
  39. hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
  40. struct snd_interval t = {
  41. .min = UINT_MAX, .max = 0, .integer = 1
  42. };
  43. unsigned int i;
  44. for (i = 0; i < SND_BEBOB_STRM_FMT_ENTRIES; i++) {
  45. /* entry is invalid */
  46. if (formations[i].pcm == 0)
  47. continue;
  48. if (!snd_interval_test(r, snd_bebob_rate_table[i]))
  49. continue;
  50. t.min = min(t.min, formations[i].pcm);
  51. t.max = max(t.max, formations[i].pcm);
  52. }
  53. return snd_interval_refine(c, &t);
  54. }
  55. static void
  56. limit_channels_and_rates(struct snd_pcm_hardware *hw,
  57. struct snd_bebob_stream_formation *formations)
  58. {
  59. unsigned int i;
  60. hw->channels_min = UINT_MAX;
  61. hw->channels_max = 0;
  62. hw->rate_min = UINT_MAX;
  63. hw->rate_max = 0;
  64. hw->rates = 0;
  65. for (i = 0; i < SND_BEBOB_STRM_FMT_ENTRIES; i++) {
  66. /* entry has no PCM channels */
  67. if (formations[i].pcm == 0)
  68. continue;
  69. hw->channels_min = min(hw->channels_min, formations[i].pcm);
  70. hw->channels_max = max(hw->channels_max, formations[i].pcm);
  71. hw->rate_min = min(hw->rate_min, snd_bebob_rate_table[i]);
  72. hw->rate_max = max(hw->rate_max, snd_bebob_rate_table[i]);
  73. hw->rates |= snd_pcm_rate_to_rate_bit(snd_bebob_rate_table[i]);
  74. }
  75. }
  76. static int
  77. pcm_init_hw_params(struct snd_bebob *bebob,
  78. struct snd_pcm_substream *substream)
  79. {
  80. struct snd_pcm_runtime *runtime = substream->runtime;
  81. struct amdtp_stream *s;
  82. struct snd_bebob_stream_formation *formations;
  83. int err;
  84. if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
  85. runtime->hw.formats = AM824_IN_PCM_FORMAT_BITS;
  86. s = &bebob->tx_stream;
  87. formations = bebob->tx_stream_formations;
  88. } else {
  89. runtime->hw.formats = AM824_OUT_PCM_FORMAT_BITS;
  90. s = &bebob->rx_stream;
  91. formations = bebob->rx_stream_formations;
  92. }
  93. limit_channels_and_rates(&runtime->hw, formations);
  94. err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
  95. hw_rule_channels, formations,
  96. SNDRV_PCM_HW_PARAM_RATE, -1);
  97. if (err < 0)
  98. goto end;
  99. err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
  100. hw_rule_rate, formations,
  101. SNDRV_PCM_HW_PARAM_CHANNELS, -1);
  102. if (err < 0)
  103. goto end;
  104. err = amdtp_am824_add_pcm_hw_constraints(s, runtime);
  105. end:
  106. return err;
  107. }
  108. static int
  109. pcm_open(struct snd_pcm_substream *substream)
  110. {
  111. struct snd_bebob *bebob = substream->private_data;
  112. const struct snd_bebob_rate_spec *spec = bebob->spec->rate;
  113. unsigned int sampling_rate;
  114. enum snd_bebob_clock_type src;
  115. int err;
  116. err = snd_bebob_stream_lock_try(bebob);
  117. if (err < 0)
  118. goto end;
  119. err = pcm_init_hw_params(bebob, substream);
  120. if (err < 0)
  121. goto err_locked;
  122. err = snd_bebob_stream_get_clock_src(bebob, &src);
  123. if (err < 0)
  124. goto err_locked;
  125. /*
  126. * When source of clock is internal or any PCM stream are running,
  127. * the available sampling rate is limited at current sampling rate.
  128. */
  129. if (src == SND_BEBOB_CLOCK_TYPE_EXTERNAL ||
  130. amdtp_stream_pcm_running(&bebob->tx_stream) ||
  131. amdtp_stream_pcm_running(&bebob->rx_stream)) {
  132. err = spec->get(bebob, &sampling_rate);
  133. if (err < 0) {
  134. dev_err(&bebob->unit->device,
  135. "fail to get sampling rate: %d\n", err);
  136. goto err_locked;
  137. }
  138. substream->runtime->hw.rate_min = sampling_rate;
  139. substream->runtime->hw.rate_max = sampling_rate;
  140. }
  141. snd_pcm_set_sync(substream);
  142. end:
  143. return err;
  144. err_locked:
  145. snd_bebob_stream_lock_release(bebob);
  146. return err;
  147. }
  148. static int
  149. pcm_close(struct snd_pcm_substream *substream)
  150. {
  151. struct snd_bebob *bebob = substream->private_data;
  152. snd_bebob_stream_lock_release(bebob);
  153. return 0;
  154. }
  155. static int
  156. pcm_capture_hw_params(struct snd_pcm_substream *substream,
  157. struct snd_pcm_hw_params *hw_params)
  158. {
  159. struct snd_bebob *bebob = substream->private_data;
  160. int err;
  161. err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
  162. params_buffer_bytes(hw_params));
  163. if (err < 0)
  164. return err;
  165. if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
  166. mutex_lock(&bebob->mutex);
  167. bebob->substreams_counter++;
  168. mutex_unlock(&bebob->mutex);
  169. }
  170. return 0;
  171. }
  172. static int
  173. pcm_playback_hw_params(struct snd_pcm_substream *substream,
  174. struct snd_pcm_hw_params *hw_params)
  175. {
  176. struct snd_bebob *bebob = substream->private_data;
  177. int err;
  178. err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
  179. params_buffer_bytes(hw_params));
  180. if (err < 0)
  181. return err;
  182. if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
  183. mutex_lock(&bebob->mutex);
  184. bebob->substreams_counter++;
  185. mutex_unlock(&bebob->mutex);
  186. }
  187. return 0;
  188. }
  189. static int
  190. pcm_capture_hw_free(struct snd_pcm_substream *substream)
  191. {
  192. struct snd_bebob *bebob = substream->private_data;
  193. if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) {
  194. mutex_lock(&bebob->mutex);
  195. bebob->substreams_counter--;
  196. mutex_unlock(&bebob->mutex);
  197. }
  198. snd_bebob_stream_stop_duplex(bebob);
  199. return snd_pcm_lib_free_vmalloc_buffer(substream);
  200. }
  201. static int
  202. pcm_playback_hw_free(struct snd_pcm_substream *substream)
  203. {
  204. struct snd_bebob *bebob = substream->private_data;
  205. if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) {
  206. mutex_lock(&bebob->mutex);
  207. bebob->substreams_counter--;
  208. mutex_unlock(&bebob->mutex);
  209. }
  210. snd_bebob_stream_stop_duplex(bebob);
  211. return snd_pcm_lib_free_vmalloc_buffer(substream);
  212. }
  213. static int
  214. pcm_capture_prepare(struct snd_pcm_substream *substream)
  215. {
  216. struct snd_bebob *bebob = substream->private_data;
  217. struct snd_pcm_runtime *runtime = substream->runtime;
  218. int err;
  219. err = snd_bebob_stream_start_duplex(bebob, runtime->rate);
  220. if (err >= 0)
  221. amdtp_stream_pcm_prepare(&bebob->tx_stream);
  222. return err;
  223. }
  224. static int
  225. pcm_playback_prepare(struct snd_pcm_substream *substream)
  226. {
  227. struct snd_bebob *bebob = substream->private_data;
  228. struct snd_pcm_runtime *runtime = substream->runtime;
  229. int err;
  230. err = snd_bebob_stream_start_duplex(bebob, runtime->rate);
  231. if (err >= 0)
  232. amdtp_stream_pcm_prepare(&bebob->rx_stream);
  233. return err;
  234. }
  235. static int
  236. pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
  237. {
  238. struct snd_bebob *bebob = substream->private_data;
  239. switch (cmd) {
  240. case SNDRV_PCM_TRIGGER_START:
  241. amdtp_stream_pcm_trigger(&bebob->tx_stream, substream);
  242. break;
  243. case SNDRV_PCM_TRIGGER_STOP:
  244. amdtp_stream_pcm_trigger(&bebob->tx_stream, NULL);
  245. break;
  246. default:
  247. return -EINVAL;
  248. }
  249. return 0;
  250. }
  251. static int
  252. pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
  253. {
  254. struct snd_bebob *bebob = substream->private_data;
  255. switch (cmd) {
  256. case SNDRV_PCM_TRIGGER_START:
  257. amdtp_stream_pcm_trigger(&bebob->rx_stream, substream);
  258. break;
  259. case SNDRV_PCM_TRIGGER_STOP:
  260. amdtp_stream_pcm_trigger(&bebob->rx_stream, NULL);
  261. break;
  262. default:
  263. return -EINVAL;
  264. }
  265. return 0;
  266. }
  267. static snd_pcm_uframes_t
  268. pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
  269. {
  270. struct snd_bebob *bebob = sbstrm->private_data;
  271. return amdtp_stream_pcm_pointer(&bebob->tx_stream);
  272. }
  273. static snd_pcm_uframes_t
  274. pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
  275. {
  276. struct snd_bebob *bebob = sbstrm->private_data;
  277. return amdtp_stream_pcm_pointer(&bebob->rx_stream);
  278. }
  279. static int pcm_capture_ack(struct snd_pcm_substream *substream)
  280. {
  281. struct snd_bebob *bebob = substream->private_data;
  282. return amdtp_stream_pcm_ack(&bebob->tx_stream);
  283. }
  284. static int pcm_playback_ack(struct snd_pcm_substream *substream)
  285. {
  286. struct snd_bebob *bebob = substream->private_data;
  287. return amdtp_stream_pcm_ack(&bebob->rx_stream);
  288. }
  289. int snd_bebob_create_pcm_devices(struct snd_bebob *bebob)
  290. {
  291. static const struct snd_pcm_ops capture_ops = {
  292. .open = pcm_open,
  293. .close = pcm_close,
  294. .ioctl = snd_pcm_lib_ioctl,
  295. .hw_params = pcm_capture_hw_params,
  296. .hw_free = pcm_capture_hw_free,
  297. .prepare = pcm_capture_prepare,
  298. .trigger = pcm_capture_trigger,
  299. .pointer = pcm_capture_pointer,
  300. .ack = pcm_capture_ack,
  301. .page = snd_pcm_lib_get_vmalloc_page,
  302. };
  303. static const struct snd_pcm_ops playback_ops = {
  304. .open = pcm_open,
  305. .close = pcm_close,
  306. .ioctl = snd_pcm_lib_ioctl,
  307. .hw_params = pcm_playback_hw_params,
  308. .hw_free = pcm_playback_hw_free,
  309. .prepare = pcm_playback_prepare,
  310. .trigger = pcm_playback_trigger,
  311. .pointer = pcm_playback_pointer,
  312. .ack = pcm_playback_ack,
  313. .page = snd_pcm_lib_get_vmalloc_page,
  314. .mmap = snd_pcm_lib_mmap_vmalloc,
  315. };
  316. struct snd_pcm *pcm;
  317. int err;
  318. err = snd_pcm_new(bebob->card, bebob->card->driver, 0, 1, 1, &pcm);
  319. if (err < 0)
  320. goto end;
  321. pcm->private_data = bebob;
  322. snprintf(pcm->name, sizeof(pcm->name),
  323. "%s PCM", bebob->card->shortname);
  324. snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
  325. snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
  326. end:
  327. return err;
  328. }