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 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
62 struct snd_pcm_hardware
*hw
= &runtime
->hw
;
63 struct amdtp_stream
*s
;
67 if (substream
->stream
== SNDRV_PCM_STREAM_CAPTURE
) {
68 substream
->runtime
->hw
.formats
= SNDRV_PCM_FMTBIT_S32
;
69 s
= &dg00x
->tx_stream
;
71 substream
->runtime
->hw
.formats
= SNDRV_PCM_FMTBIT_S32
;
72 s
= &dg00x
->rx_stream
;
75 hw
->channels_min
= 10;
76 hw
->channels_max
= 18;
78 hw
->rates
= SNDRV_PCM_RATE_44100
|
79 SNDRV_PCM_RATE_48000
|
80 SNDRV_PCM_RATE_88200
|
82 snd_pcm_limit_hw_rates(runtime
);
84 err
= snd_pcm_hw_rule_add(substream
->runtime
, 0,
85 SNDRV_PCM_HW_PARAM_CHANNELS
,
86 hw_rule_channels
, NULL
,
87 SNDRV_PCM_HW_PARAM_RATE
, -1);
91 err
= snd_pcm_hw_rule_add(substream
->runtime
, 0,
92 SNDRV_PCM_HW_PARAM_RATE
,
94 SNDRV_PCM_HW_PARAM_CHANNELS
, -1);
98 return amdtp_dot_add_pcm_hw_constraints(s
, substream
->runtime
);
101 static int pcm_open(struct snd_pcm_substream
*substream
)
103 struct snd_dg00x
*dg00x
= substream
->private_data
;
104 enum snd_dg00x_clock clock
;
109 err
= snd_dg00x_stream_lock_try(dg00x
);
113 err
= pcm_init_hw_params(dg00x
, substream
);
117 /* Check current clock source. */
118 err
= snd_dg00x_stream_get_clock(dg00x
, &clock
);
121 if (clock
!= SND_DG00X_CLOCK_INTERNAL
) {
122 err
= snd_dg00x_stream_check_external_clock(dg00x
, &detect
);
131 if ((clock
!= SND_DG00X_CLOCK_INTERNAL
) ||
132 amdtp_stream_pcm_running(&dg00x
->rx_stream
) ||
133 amdtp_stream_pcm_running(&dg00x
->tx_stream
)) {
134 err
= snd_dg00x_stream_get_external_rate(dg00x
, &rate
);
137 substream
->runtime
->hw
.rate_min
= rate
;
138 substream
->runtime
->hw
.rate_max
= rate
;
141 snd_pcm_set_sync(substream
);
145 snd_dg00x_stream_lock_release(dg00x
);
149 static int pcm_close(struct snd_pcm_substream
*substream
)
151 struct snd_dg00x
*dg00x
= substream
->private_data
;
153 snd_dg00x_stream_lock_release(dg00x
);
158 static int pcm_capture_hw_params(struct snd_pcm_substream
*substream
,
159 struct snd_pcm_hw_params
*hw_params
)
161 struct snd_dg00x
*dg00x
= substream
->private_data
;
164 err
= snd_pcm_lib_alloc_vmalloc_buffer(substream
,
165 params_buffer_bytes(hw_params
));
169 if (substream
->runtime
->status
->state
== SNDRV_PCM_STATE_OPEN
) {
170 mutex_lock(&dg00x
->mutex
);
171 dg00x
->substreams_counter
++;
172 mutex_unlock(&dg00x
->mutex
);
178 static int pcm_playback_hw_params(struct snd_pcm_substream
*substream
,
179 struct snd_pcm_hw_params
*hw_params
)
181 struct snd_dg00x
*dg00x
= substream
->private_data
;
184 err
= snd_pcm_lib_alloc_vmalloc_buffer(substream
,
185 params_buffer_bytes(hw_params
));
189 if (substream
->runtime
->status
->state
== SNDRV_PCM_STATE_OPEN
) {
190 mutex_lock(&dg00x
->mutex
);
191 dg00x
->substreams_counter
++;
192 mutex_unlock(&dg00x
->mutex
);
198 static int pcm_capture_hw_free(struct snd_pcm_substream
*substream
)
200 struct snd_dg00x
*dg00x
= substream
->private_data
;
202 mutex_lock(&dg00x
->mutex
);
204 if (substream
->runtime
->status
->state
!= SNDRV_PCM_STATE_OPEN
)
205 dg00x
->substreams_counter
--;
207 snd_dg00x_stream_stop_duplex(dg00x
);
209 mutex_unlock(&dg00x
->mutex
);
211 return snd_pcm_lib_free_vmalloc_buffer(substream
);
214 static int pcm_playback_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_capture_prepare(struct snd_pcm_substream
*substream
)
232 struct snd_dg00x
*dg00x
= substream
->private_data
;
233 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
236 mutex_lock(&dg00x
->mutex
);
238 err
= snd_dg00x_stream_start_duplex(dg00x
, runtime
->rate
);
240 amdtp_stream_pcm_prepare(&dg00x
->tx_stream
);
242 mutex_unlock(&dg00x
->mutex
);
247 static int pcm_playback_prepare(struct snd_pcm_substream
*substream
)
249 struct snd_dg00x
*dg00x
= substream
->private_data
;
250 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
253 mutex_lock(&dg00x
->mutex
);
255 err
= snd_dg00x_stream_start_duplex(dg00x
, runtime
->rate
);
257 amdtp_stream_pcm_prepare(&dg00x
->rx_stream
);
258 amdtp_dot_reset(&dg00x
->rx_stream
);
261 mutex_unlock(&dg00x
->mutex
);
266 static int pcm_capture_trigger(struct snd_pcm_substream
*substream
, int cmd
)
268 struct snd_dg00x
*dg00x
= substream
->private_data
;
271 case SNDRV_PCM_TRIGGER_START
:
272 amdtp_stream_pcm_trigger(&dg00x
->tx_stream
, substream
);
274 case SNDRV_PCM_TRIGGER_STOP
:
275 amdtp_stream_pcm_trigger(&dg00x
->tx_stream
, NULL
);
284 static int pcm_playback_trigger(struct snd_pcm_substream
*substream
, int cmd
)
286 struct snd_dg00x
*dg00x
= substream
->private_data
;
289 case SNDRV_PCM_TRIGGER_START
:
290 amdtp_stream_pcm_trigger(&dg00x
->rx_stream
, substream
);
292 case SNDRV_PCM_TRIGGER_STOP
:
293 amdtp_stream_pcm_trigger(&dg00x
->rx_stream
, NULL
);
302 static snd_pcm_uframes_t
pcm_capture_pointer(struct snd_pcm_substream
*sbstrm
)
304 struct snd_dg00x
*dg00x
= sbstrm
->private_data
;
306 return amdtp_stream_pcm_pointer(&dg00x
->tx_stream
);
309 static snd_pcm_uframes_t
pcm_playback_pointer(struct snd_pcm_substream
*sbstrm
)
311 struct snd_dg00x
*dg00x
= sbstrm
->private_data
;
313 return amdtp_stream_pcm_pointer(&dg00x
->rx_stream
);
316 static int pcm_capture_ack(struct snd_pcm_substream
*substream
)
318 struct snd_dg00x
*dg00x
= substream
->private_data
;
320 return amdtp_stream_pcm_ack(&dg00x
->tx_stream
);
323 static int pcm_playback_ack(struct snd_pcm_substream
*substream
)
325 struct snd_dg00x
*dg00x
= substream
->private_data
;
327 return amdtp_stream_pcm_ack(&dg00x
->rx_stream
);
330 int snd_dg00x_create_pcm_devices(struct snd_dg00x
*dg00x
)
332 static const struct snd_pcm_ops 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 .ack
= pcm_capture_ack
,
342 .page
= snd_pcm_lib_get_vmalloc_page
,
344 static const struct snd_pcm_ops 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 .ack
= pcm_playback_ack
,
354 .page
= snd_pcm_lib_get_vmalloc_page
,
355 .mmap
= snd_pcm_lib_mmap_vmalloc
,
360 err
= snd_pcm_new(dg00x
->card
, dg00x
->card
->driver
, 0, 1, 1, &pcm
);
364 pcm
->private_data
= dg00x
;
365 snprintf(pcm
->name
, sizeof(pcm
->name
),
366 "%s PCM", dg00x
->card
->shortname
);
367 snd_pcm_set_ops(pcm
, SNDRV_PCM_STREAM_PLAYBACK
, &playback_ops
);
368 snd_pcm_set_ops(pcm
, SNDRV_PCM_STREAM_CAPTURE
, &capture_ops
);