1 // SPDX-License-Identifier: GPL-2.0-only
3 * digi00x-pcm.c - a part of driver for Digidesign Digi 002/003 family
5 * Copyright (c) 2014-2015 Takashi Sakamoto
10 static int hw_rule_rate(struct snd_pcm_hw_params
*params
,
11 struct snd_pcm_hw_rule
*rule
)
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,
22 for (i
= 0; i
< SND_DG00X_RATE_COUNT
; i
++) {
23 if (!snd_interval_test(c
,
24 snd_dg00x_stream_pcm_channels
[i
]))
27 t
.min
= min(t
.min
, snd_dg00x_stream_rates
[i
]);
28 t
.max
= max(t
.max
, snd_dg00x_stream_rates
[i
]);
31 return snd_interval_refine(r
, &t
);
34 static int hw_rule_channels(struct snd_pcm_hw_params
*params
,
35 struct snd_pcm_hw_rule
*rule
)
37 struct snd_interval
*c
=
38 hw_param_interval(params
, SNDRV_PCM_HW_PARAM_CHANNELS
);
39 const struct snd_interval
*r
=
40 hw_param_interval_c(params
, SNDRV_PCM_HW_PARAM_RATE
);
41 struct snd_interval t
= {
42 .min
= UINT_MAX
, .max
= 0, .integer
= 1,
46 for (i
= 0; i
< SND_DG00X_RATE_COUNT
; i
++) {
47 if (!snd_interval_test(r
, snd_dg00x_stream_rates
[i
]))
50 t
.min
= min(t
.min
, snd_dg00x_stream_pcm_channels
[i
]);
51 t
.max
= max(t
.max
, snd_dg00x_stream_pcm_channels
[i
]);
54 return snd_interval_refine(c
, &t
);
57 static int pcm_init_hw_params(struct snd_dg00x
*dg00x
,
58 struct snd_pcm_substream
*substream
)
60 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
61 struct snd_pcm_hardware
*hw
= &runtime
->hw
;
62 struct amdtp_stream
*s
;
66 if (substream
->stream
== SNDRV_PCM_STREAM_CAPTURE
) {
67 substream
->runtime
->hw
.formats
= SNDRV_PCM_FMTBIT_S32
;
68 s
= &dg00x
->tx_stream
;
70 substream
->runtime
->hw
.formats
= SNDRV_PCM_FMTBIT_S32
;
71 s
= &dg00x
->rx_stream
;
74 hw
->channels_min
= 10;
75 hw
->channels_max
= 18;
77 hw
->rates
= SNDRV_PCM_RATE_44100
|
78 SNDRV_PCM_RATE_48000
|
79 SNDRV_PCM_RATE_88200
|
81 snd_pcm_limit_hw_rates(runtime
);
83 err
= snd_pcm_hw_rule_add(substream
->runtime
, 0,
84 SNDRV_PCM_HW_PARAM_CHANNELS
,
85 hw_rule_channels
, NULL
,
86 SNDRV_PCM_HW_PARAM_RATE
, -1);
90 err
= snd_pcm_hw_rule_add(substream
->runtime
, 0,
91 SNDRV_PCM_HW_PARAM_RATE
,
93 SNDRV_PCM_HW_PARAM_CHANNELS
, -1);
97 return amdtp_dot_add_pcm_hw_constraints(s
, substream
->runtime
);
100 static int pcm_open(struct snd_pcm_substream
*substream
)
102 struct snd_dg00x
*dg00x
= substream
->private_data
;
103 struct amdtp_domain
*d
= &dg00x
->domain
;
104 enum snd_dg00x_clock clock
;
108 err
= snd_dg00x_stream_lock_try(dg00x
);
112 err
= pcm_init_hw_params(dg00x
, substream
);
116 /* Check current clock source. */
117 err
= snd_dg00x_stream_get_clock(dg00x
, &clock
);
120 if (clock
!= SND_DG00X_CLOCK_INTERNAL
) {
121 err
= snd_dg00x_stream_check_external_clock(dg00x
, &detect
);
130 mutex_lock(&dg00x
->mutex
);
132 // When source of clock is not internal or any stream is reserved for
133 // transmission of PCM frames, the available sampling rate is limited
135 if ((clock
!= SND_DG00X_CLOCK_INTERNAL
) ||
136 (dg00x
->substreams_counter
> 0 && d
->events_per_period
> 0)) {
137 unsigned int frames_per_period
= d
->events_per_period
;
138 unsigned int frames_per_buffer
= d
->events_per_buffer
;
141 err
= snd_dg00x_stream_get_external_rate(dg00x
, &rate
);
143 mutex_unlock(&dg00x
->mutex
);
146 substream
->runtime
->hw
.rate_min
= rate
;
147 substream
->runtime
->hw
.rate_max
= rate
;
149 if (frames_per_period
> 0) {
150 err
= snd_pcm_hw_constraint_minmax(substream
->runtime
,
151 SNDRV_PCM_HW_PARAM_PERIOD_SIZE
,
152 frames_per_period
, frames_per_period
);
154 mutex_unlock(&dg00x
->mutex
);
158 err
= snd_pcm_hw_constraint_minmax(substream
->runtime
,
159 SNDRV_PCM_HW_PARAM_BUFFER_SIZE
,
160 frames_per_buffer
, frames_per_buffer
);
162 mutex_unlock(&dg00x
->mutex
);
168 mutex_unlock(&dg00x
->mutex
);
170 snd_pcm_set_sync(substream
);
174 snd_dg00x_stream_lock_release(dg00x
);
178 static int pcm_close(struct snd_pcm_substream
*substream
)
180 struct snd_dg00x
*dg00x
= substream
->private_data
;
182 snd_dg00x_stream_lock_release(dg00x
);
187 static int pcm_hw_params(struct snd_pcm_substream
*substream
,
188 struct snd_pcm_hw_params
*hw_params
)
190 struct snd_dg00x
*dg00x
= substream
->private_data
;
193 if (substream
->runtime
->status
->state
== SNDRV_PCM_STATE_OPEN
) {
194 unsigned int rate
= params_rate(hw_params
);
195 unsigned int frames_per_period
= params_period_size(hw_params
);
196 unsigned int frames_per_buffer
= params_buffer_size(hw_params
);
198 mutex_lock(&dg00x
->mutex
);
199 err
= snd_dg00x_stream_reserve_duplex(dg00x
, rate
,
200 frames_per_period
, frames_per_buffer
);
202 ++dg00x
->substreams_counter
;
203 mutex_unlock(&dg00x
->mutex
);
209 static int pcm_hw_free(struct snd_pcm_substream
*substream
)
211 struct snd_dg00x
*dg00x
= substream
->private_data
;
213 mutex_lock(&dg00x
->mutex
);
215 if (substream
->runtime
->status
->state
!= SNDRV_PCM_STATE_OPEN
)
216 --dg00x
->substreams_counter
;
218 snd_dg00x_stream_stop_duplex(dg00x
);
220 mutex_unlock(&dg00x
->mutex
);
225 static int pcm_capture_prepare(struct snd_pcm_substream
*substream
)
227 struct snd_dg00x
*dg00x
= substream
->private_data
;
230 mutex_lock(&dg00x
->mutex
);
232 err
= snd_dg00x_stream_start_duplex(dg00x
);
234 amdtp_stream_pcm_prepare(&dg00x
->tx_stream
);
236 mutex_unlock(&dg00x
->mutex
);
241 static int pcm_playback_prepare(struct snd_pcm_substream
*substream
)
243 struct snd_dg00x
*dg00x
= substream
->private_data
;
246 mutex_lock(&dg00x
->mutex
);
248 err
= snd_dg00x_stream_start_duplex(dg00x
);
250 amdtp_stream_pcm_prepare(&dg00x
->rx_stream
);
251 amdtp_dot_reset(&dg00x
->rx_stream
);
254 mutex_unlock(&dg00x
->mutex
);
259 static int pcm_capture_trigger(struct snd_pcm_substream
*substream
, int cmd
)
261 struct snd_dg00x
*dg00x
= substream
->private_data
;
264 case SNDRV_PCM_TRIGGER_START
:
265 amdtp_stream_pcm_trigger(&dg00x
->tx_stream
, substream
);
267 case SNDRV_PCM_TRIGGER_STOP
:
268 amdtp_stream_pcm_trigger(&dg00x
->tx_stream
, NULL
);
277 static int pcm_playback_trigger(struct snd_pcm_substream
*substream
, int cmd
)
279 struct snd_dg00x
*dg00x
= substream
->private_data
;
282 case SNDRV_PCM_TRIGGER_START
:
283 amdtp_stream_pcm_trigger(&dg00x
->rx_stream
, substream
);
285 case SNDRV_PCM_TRIGGER_STOP
:
286 amdtp_stream_pcm_trigger(&dg00x
->rx_stream
, NULL
);
295 static snd_pcm_uframes_t
pcm_capture_pointer(struct snd_pcm_substream
*sbstrm
)
297 struct snd_dg00x
*dg00x
= sbstrm
->private_data
;
299 return amdtp_domain_stream_pcm_pointer(&dg00x
->domain
, &dg00x
->tx_stream
);
302 static snd_pcm_uframes_t
pcm_playback_pointer(struct snd_pcm_substream
*sbstrm
)
304 struct snd_dg00x
*dg00x
= sbstrm
->private_data
;
306 return amdtp_domain_stream_pcm_pointer(&dg00x
->domain
, &dg00x
->rx_stream
);
309 static int pcm_capture_ack(struct snd_pcm_substream
*substream
)
311 struct snd_dg00x
*dg00x
= substream
->private_data
;
313 return amdtp_domain_stream_pcm_ack(&dg00x
->domain
, &dg00x
->tx_stream
);
316 static int pcm_playback_ack(struct snd_pcm_substream
*substream
)
318 struct snd_dg00x
*dg00x
= substream
->private_data
;
320 return amdtp_domain_stream_pcm_ack(&dg00x
->domain
, &dg00x
->rx_stream
);
323 int snd_dg00x_create_pcm_devices(struct snd_dg00x
*dg00x
)
325 static const struct snd_pcm_ops capture_ops
= {
328 .hw_params
= pcm_hw_params
,
329 .hw_free
= pcm_hw_free
,
330 .prepare
= pcm_capture_prepare
,
331 .trigger
= pcm_capture_trigger
,
332 .pointer
= pcm_capture_pointer
,
333 .ack
= pcm_capture_ack
,
335 static const struct snd_pcm_ops playback_ops
= {
338 .hw_params
= pcm_hw_params
,
339 .hw_free
= pcm_hw_free
,
340 .prepare
= pcm_playback_prepare
,
341 .trigger
= pcm_playback_trigger
,
342 .pointer
= pcm_playback_pointer
,
343 .ack
= pcm_playback_ack
,
348 err
= snd_pcm_new(dg00x
->card
, dg00x
->card
->driver
, 0, 1, 1, &pcm
);
352 pcm
->private_data
= dg00x
;
353 snprintf(pcm
->name
, sizeof(pcm
->name
),
354 "%s PCM", dg00x
->card
->shortname
);
355 snd_pcm_set_ops(pcm
, SNDRV_PCM_STREAM_PLAYBACK
, &playback_ops
);
356 snd_pcm_set_ops(pcm
, SNDRV_PCM_STREAM_CAPTURE
, &capture_ops
);
357 snd_pcm_set_managed_buffer_all(pcm
, SNDRV_DMA_TYPE_VMALLOC
, NULL
, 0, 0);