2 * digi00x-pcm.c - a part of driver for Digidesign Digi 002/003 family
4 * Copyright (c) 2014-2015 Takashi Sakamoto
6 * Licensed under the terms of the GNU General Public License, version 2.
11 static int hw_rule_rate(struct snd_pcm_hw_params
*params
,
12 struct snd_pcm_hw_rule
*rule
)
14 struct snd_interval
*r
=
15 hw_param_interval(params
, SNDRV_PCM_HW_PARAM_RATE
);
16 const struct snd_interval
*c
=
17 hw_param_interval_c(params
, SNDRV_PCM_HW_PARAM_CHANNELS
);
18 struct snd_interval t
= {
19 .min
= UINT_MAX
, .max
= 0, .integer
= 1,
23 for (i
= 0; i
< SND_DG00X_RATE_COUNT
; i
++) {
24 if (!snd_interval_test(c
,
25 snd_dg00x_stream_pcm_channels
[i
]))
28 t
.min
= min(t
.min
, snd_dg00x_stream_rates
[i
]);
29 t
.max
= max(t
.max
, snd_dg00x_stream_rates
[i
]);
32 return snd_interval_refine(r
, &t
);
35 static int hw_rule_channels(struct snd_pcm_hw_params
*params
,
36 struct snd_pcm_hw_rule
*rule
)
38 struct snd_interval
*c
=
39 hw_param_interval(params
, SNDRV_PCM_HW_PARAM_CHANNELS
);
40 const struct snd_interval
*r
=
41 hw_param_interval_c(params
, SNDRV_PCM_HW_PARAM_RATE
);
42 struct snd_interval t
= {
43 .min
= UINT_MAX
, .max
= 0, .integer
= 1,
47 for (i
= 0; i
< SND_DG00X_RATE_COUNT
; i
++) {
48 if (!snd_interval_test(r
, snd_dg00x_stream_rates
[i
]))
51 t
.min
= min(t
.min
, snd_dg00x_stream_pcm_channels
[i
]);
52 t
.max
= max(t
.max
, snd_dg00x_stream_pcm_channels
[i
]);
55 return snd_interval_refine(c
, &t
);
58 static int pcm_init_hw_params(struct snd_dg00x
*dg00x
,
59 struct snd_pcm_substream
*substream
)
61 static const struct snd_pcm_hardware hardware
= {
62 .info
= SNDRV_PCM_INFO_BATCH
|
63 SNDRV_PCM_INFO_BLOCK_TRANSFER
|
64 SNDRV_PCM_INFO_INTERLEAVED
|
65 SNDRV_PCM_INFO_JOINT_DUPLEX
|
67 SNDRV_PCM_INFO_MMAP_VALID
,
68 .rates
= SNDRV_PCM_RATE_44100
|
69 SNDRV_PCM_RATE_48000
|
70 SNDRV_PCM_RATE_88200
|
76 .period_bytes_min
= 4 * 18,
77 .period_bytes_max
= 4 * 18 * 2048,
78 .buffer_bytes_max
= 4 * 18 * 2048 * 2,
80 .periods_max
= UINT_MAX
,
82 struct amdtp_stream
*s
;
85 substream
->runtime
->hw
= hardware
;
87 if (substream
->stream
== SNDRV_PCM_STREAM_CAPTURE
) {
88 substream
->runtime
->hw
.formats
= SNDRV_PCM_FMTBIT_S32
;
89 s
= &dg00x
->tx_stream
;
91 substream
->runtime
->hw
.formats
= SNDRV_PCM_FMTBIT_S16
|
93 s
= &dg00x
->rx_stream
;
96 err
= snd_pcm_hw_rule_add(substream
->runtime
, 0,
97 SNDRV_PCM_HW_PARAM_CHANNELS
,
98 hw_rule_channels
, NULL
,
99 SNDRV_PCM_HW_PARAM_RATE
, -1);
103 err
= snd_pcm_hw_rule_add(substream
->runtime
, 0,
104 SNDRV_PCM_HW_PARAM_RATE
,
106 SNDRV_PCM_HW_PARAM_CHANNELS
, -1);
110 return amdtp_dot_add_pcm_hw_constraints(s
, substream
->runtime
);
113 static int pcm_open(struct snd_pcm_substream
*substream
)
115 struct snd_dg00x
*dg00x
= substream
->private_data
;
116 enum snd_dg00x_clock clock
;
121 err
= snd_dg00x_stream_lock_try(dg00x
);
125 err
= pcm_init_hw_params(dg00x
, substream
);
129 /* Check current clock source. */
130 err
= snd_dg00x_stream_get_clock(dg00x
, &clock
);
133 if (clock
!= SND_DG00X_CLOCK_INTERNAL
) {
134 err
= snd_dg00x_stream_check_external_clock(dg00x
, &detect
);
143 if ((clock
!= SND_DG00X_CLOCK_INTERNAL
) ||
144 amdtp_stream_pcm_running(&dg00x
->rx_stream
) ||
145 amdtp_stream_pcm_running(&dg00x
->tx_stream
)) {
146 err
= snd_dg00x_stream_get_external_rate(dg00x
, &rate
);
149 substream
->runtime
->hw
.rate_min
= rate
;
150 substream
->runtime
->hw
.rate_max
= rate
;
153 snd_pcm_set_sync(substream
);
157 snd_dg00x_stream_lock_release(dg00x
);
161 static int pcm_close(struct snd_pcm_substream
*substream
)
163 struct snd_dg00x
*dg00x
= substream
->private_data
;
165 snd_dg00x_stream_lock_release(dg00x
);
170 static int pcm_capture_hw_params(struct snd_pcm_substream
*substream
,
171 struct snd_pcm_hw_params
*hw_params
)
173 struct snd_dg00x
*dg00x
= substream
->private_data
;
176 err
= snd_pcm_lib_alloc_vmalloc_buffer(substream
,
177 params_buffer_bytes(hw_params
));
181 if (substream
->runtime
->status
->state
== SNDRV_PCM_STATE_OPEN
) {
182 mutex_lock(&dg00x
->mutex
);
183 dg00x
->substreams_counter
++;
184 mutex_unlock(&dg00x
->mutex
);
187 amdtp_dot_set_pcm_format(&dg00x
->tx_stream
, params_format(hw_params
));
192 static int pcm_playback_hw_params(struct snd_pcm_substream
*substream
,
193 struct snd_pcm_hw_params
*hw_params
)
195 struct snd_dg00x
*dg00x
= substream
->private_data
;
198 err
= snd_pcm_lib_alloc_vmalloc_buffer(substream
,
199 params_buffer_bytes(hw_params
));
203 if (substream
->runtime
->status
->state
== SNDRV_PCM_STATE_OPEN
) {
204 mutex_lock(&dg00x
->mutex
);
205 dg00x
->substreams_counter
++;
206 mutex_unlock(&dg00x
->mutex
);
209 amdtp_dot_set_pcm_format(&dg00x
->rx_stream
, params_format(hw_params
));
214 static int pcm_capture_hw_free(struct snd_pcm_substream
*substream
)
216 struct snd_dg00x
*dg00x
= substream
->private_data
;
218 mutex_lock(&dg00x
->mutex
);
220 if (substream
->runtime
->status
->state
!= SNDRV_PCM_STATE_OPEN
)
221 dg00x
->substreams_counter
--;
223 snd_dg00x_stream_stop_duplex(dg00x
);
225 mutex_unlock(&dg00x
->mutex
);
227 return snd_pcm_lib_free_vmalloc_buffer(substream
);
230 static int pcm_playback_hw_free(struct snd_pcm_substream
*substream
)
232 struct snd_dg00x
*dg00x
= substream
->private_data
;
234 mutex_lock(&dg00x
->mutex
);
236 if (substream
->runtime
->status
->state
!= SNDRV_PCM_STATE_OPEN
)
237 dg00x
->substreams_counter
--;
239 snd_dg00x_stream_stop_duplex(dg00x
);
241 mutex_unlock(&dg00x
->mutex
);
243 return snd_pcm_lib_free_vmalloc_buffer(substream
);
246 static int pcm_capture_prepare(struct snd_pcm_substream
*substream
)
248 struct snd_dg00x
*dg00x
= substream
->private_data
;
249 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
252 mutex_lock(&dg00x
->mutex
);
254 err
= snd_dg00x_stream_start_duplex(dg00x
, runtime
->rate
);
256 amdtp_stream_pcm_prepare(&dg00x
->tx_stream
);
258 mutex_unlock(&dg00x
->mutex
);
263 static int pcm_playback_prepare(struct snd_pcm_substream
*substream
)
265 struct snd_dg00x
*dg00x
= substream
->private_data
;
266 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
269 mutex_lock(&dg00x
->mutex
);
271 err
= snd_dg00x_stream_start_duplex(dg00x
, runtime
->rate
);
273 amdtp_stream_pcm_prepare(&dg00x
->rx_stream
);
274 amdtp_dot_reset(&dg00x
->rx_stream
);
277 mutex_unlock(&dg00x
->mutex
);
282 static int pcm_capture_trigger(struct snd_pcm_substream
*substream
, int cmd
)
284 struct snd_dg00x
*dg00x
= substream
->private_data
;
287 case SNDRV_PCM_TRIGGER_START
:
288 amdtp_stream_pcm_trigger(&dg00x
->tx_stream
, substream
);
290 case SNDRV_PCM_TRIGGER_STOP
:
291 amdtp_stream_pcm_trigger(&dg00x
->tx_stream
, NULL
);
300 static int pcm_playback_trigger(struct snd_pcm_substream
*substream
, int cmd
)
302 struct snd_dg00x
*dg00x
= substream
->private_data
;
305 case SNDRV_PCM_TRIGGER_START
:
306 amdtp_stream_pcm_trigger(&dg00x
->rx_stream
, substream
);
308 case SNDRV_PCM_TRIGGER_STOP
:
309 amdtp_stream_pcm_trigger(&dg00x
->rx_stream
, NULL
);
318 static snd_pcm_uframes_t
pcm_capture_pointer(struct snd_pcm_substream
*sbstrm
)
320 struct snd_dg00x
*dg00x
= sbstrm
->private_data
;
322 return amdtp_stream_pcm_pointer(&dg00x
->tx_stream
);
325 static snd_pcm_uframes_t
pcm_playback_pointer(struct snd_pcm_substream
*sbstrm
)
327 struct snd_dg00x
*dg00x
= sbstrm
->private_data
;
329 return amdtp_stream_pcm_pointer(&dg00x
->rx_stream
);
332 static const struct snd_pcm_ops pcm_capture_ops
= {
335 .ioctl
= snd_pcm_lib_ioctl
,
336 .hw_params
= pcm_capture_hw_params
,
337 .hw_free
= pcm_capture_hw_free
,
338 .prepare
= pcm_capture_prepare
,
339 .trigger
= pcm_capture_trigger
,
340 .pointer
= pcm_capture_pointer
,
341 .page
= snd_pcm_lib_get_vmalloc_page
,
344 static const struct snd_pcm_ops pcm_playback_ops
= {
347 .ioctl
= snd_pcm_lib_ioctl
,
348 .hw_params
= pcm_playback_hw_params
,
349 .hw_free
= pcm_playback_hw_free
,
350 .prepare
= pcm_playback_prepare
,
351 .trigger
= pcm_playback_trigger
,
352 .pointer
= pcm_playback_pointer
,
353 .page
= snd_pcm_lib_get_vmalloc_page
,
354 .mmap
= snd_pcm_lib_mmap_vmalloc
,
357 int snd_dg00x_create_pcm_devices(struct snd_dg00x
*dg00x
)
362 err
= snd_pcm_new(dg00x
->card
, dg00x
->card
->driver
, 0, 1, 1, &pcm
);
366 pcm
->private_data
= dg00x
;
367 snprintf(pcm
->name
, sizeof(pcm
->name
),
368 "%s PCM", dg00x
->card
->shortname
);
369 snd_pcm_set_ops(pcm
, SNDRV_PCM_STREAM_PLAYBACK
, &pcm_playback_ops
);
370 snd_pcm_set_ops(pcm
, SNDRV_PCM_STREAM_CAPTURE
, &pcm_capture_ops
);