aboutsummaryrefslogtreecommitdiffstats
path: root/sound/firewire
diff options
context:
space:
mode:
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>2014-11-28 10:59:28 -0500
committerTakashi Iwai <tiwai@suse.de>2014-11-29 14:22:22 -0500
commit3713d93a6a12f8629c2660bb4a30d48b98105fca (patch)
tree2d4ddd4be53f7eb7016094ccbdca8c0e6f553cd8 /sound/firewire
parente2786ca648d780d106bd8abca06746eb30d15ee7 (diff)
ALSA: oxfw: Split PCM functionality to a new file
This is a help for works in followed patches. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/firewire')
-rw-r--r--sound/firewire/oxfw/Makefile2
-rw-r--r--sound/firewire/oxfw/oxfw-pcm.c249
-rw-r--r--sound/firewire/oxfw/oxfw.c240
-rw-r--r--sound/firewire/oxfw/oxfw.h4
4 files changed, 255 insertions, 240 deletions
diff --git a/sound/firewire/oxfw/Makefile b/sound/firewire/oxfw/Makefile
index e15c4c07b49d..7fb4d09a5f07 100644
--- a/sound/firewire/oxfw/Makefile
+++ b/sound/firewire/oxfw/Makefile
@@ -1,2 +1,2 @@
1snd-oxfw-objs := oxfw-stream.o oxfw.o 1snd-oxfw-objs := oxfw-stream.o oxfw-pcm.o oxfw.o
2obj-m += snd-oxfw.o 2obj-m += snd-oxfw.o
diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c
new file mode 100644
index 000000000000..d39f17a8f8c0
--- /dev/null
+++ b/sound/firewire/oxfw/oxfw-pcm.c
@@ -0,0 +1,249 @@
1/*
2 * oxfw_pcm.c - a part of driver for OXFW970/971 based devices
3 *
4 * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
5 * Licensed under the terms of the GNU General Public License, version 2.
6 */
7
8#include "oxfw.h"
9
10static int firewave_rate_constraint(struct snd_pcm_hw_params *params,
11 struct snd_pcm_hw_rule *rule)
12{
13 static unsigned int stereo_rates[] = { 48000, 96000 };
14 struct snd_interval *channels =
15 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
16 struct snd_interval *rate =
17 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
18
19 /* two channels work only at 48/96 kHz */
20 if (snd_interval_max(channels) < 6)
21 return snd_interval_list(rate, 2, stereo_rates, 0);
22 return 0;
23}
24
25static int firewave_channels_constraint(struct snd_pcm_hw_params *params,
26 struct snd_pcm_hw_rule *rule)
27{
28 static const struct snd_interval all_channels = { .min = 6, .max = 6 };
29 struct snd_interval *rate =
30 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
31 struct snd_interval *channels =
32 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
33
34 /* 32/44.1 kHz work only with all six channels */
35 if (snd_interval_max(rate) < 48000)
36 return snd_interval_refine(channels, &all_channels);
37 return 0;
38}
39
40int firewave_constraints(struct snd_pcm_runtime *runtime)
41{
42 static unsigned int channels_list[] = { 2, 6 };
43 static struct snd_pcm_hw_constraint_list channels_list_constraint = {
44 .count = 2,
45 .list = channels_list,
46 };
47 int err;
48
49 runtime->hw.rates = SNDRV_PCM_RATE_32000 |
50 SNDRV_PCM_RATE_44100 |
51 SNDRV_PCM_RATE_48000 |
52 SNDRV_PCM_RATE_96000;
53 runtime->hw.channels_max = 6;
54
55 err = snd_pcm_hw_constraint_list(runtime, 0,
56 SNDRV_PCM_HW_PARAM_CHANNELS,
57 &channels_list_constraint);
58 if (err < 0)
59 return err;
60 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
61 firewave_rate_constraint, NULL,
62 SNDRV_PCM_HW_PARAM_CHANNELS, -1);
63 if (err < 0)
64 return err;
65 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
66 firewave_channels_constraint, NULL,
67 SNDRV_PCM_HW_PARAM_RATE, -1);
68 if (err < 0)
69 return err;
70
71 return 0;
72}
73
74int lacie_speakers_constraints(struct snd_pcm_runtime *runtime)
75{
76 runtime->hw.rates = SNDRV_PCM_RATE_32000 |
77 SNDRV_PCM_RATE_44100 |
78 SNDRV_PCM_RATE_48000 |
79 SNDRV_PCM_RATE_88200 |
80 SNDRV_PCM_RATE_96000;
81
82 return 0;
83}
84
85static int pcm_open(struct snd_pcm_substream *substream)
86{
87 static const struct snd_pcm_hardware hardware = {
88 .info = SNDRV_PCM_INFO_MMAP |
89 SNDRV_PCM_INFO_MMAP_VALID |
90 SNDRV_PCM_INFO_BATCH |
91 SNDRV_PCM_INFO_INTERLEAVED |
92 SNDRV_PCM_INFO_BLOCK_TRANSFER,
93 .formats = AMDTP_OUT_PCM_FORMAT_BITS,
94 .channels_min = 2,
95 .channels_max = 2,
96 .buffer_bytes_max = 4 * 1024 * 1024,
97 .period_bytes_min = 1,
98 .period_bytes_max = UINT_MAX,
99 .periods_min = 1,
100 .periods_max = UINT_MAX,
101 };
102 struct snd_oxfw *oxfw = substream->private_data;
103 struct snd_pcm_runtime *runtime = substream->runtime;
104 bool used;
105 int err;
106
107 err = cmp_connection_check_used(&oxfw->in_conn, &used);
108 if ((err < 0) || used)
109 goto end;
110
111 runtime->hw = hardware;
112
113 err = oxfw->device_info->pcm_constraints(runtime);
114 if (err < 0)
115 goto end;
116 err = snd_pcm_limit_hw_rates(runtime);
117 if (err < 0)
118 goto end;
119
120 err = amdtp_stream_add_pcm_hw_constraints(&oxfw->rx_stream, runtime);
121end:
122 return err;
123}
124
125static int pcm_close(struct snd_pcm_substream *substream)
126{
127 return 0;
128}
129
130static int pcm_hw_params(struct snd_pcm_substream *substream,
131 struct snd_pcm_hw_params *hw_params)
132{
133 struct snd_oxfw *oxfw = substream->private_data;
134 int err;
135
136 mutex_lock(&oxfw->mutex);
137
138 snd_oxfw_stream_stop_simplex(oxfw);
139
140 err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
141 params_buffer_bytes(hw_params));
142 if (err < 0)
143 goto error;
144
145 amdtp_stream_set_parameters(&oxfw->rx_stream,
146 params_rate(hw_params),
147 params_channels(hw_params),
148 0);
149
150 amdtp_stream_set_pcm_format(&oxfw->rx_stream,
151 params_format(hw_params));
152
153 err = avc_general_set_sig_fmt(oxfw->unit, params_rate(hw_params),
154 AVC_GENERAL_PLUG_DIR_IN, 0);
155 if (err < 0) {
156 dev_err(&oxfw->unit->device, "failed to set sample rate\n");
157 goto err_buffer;
158 }
159
160 return 0;
161
162err_buffer:
163 snd_pcm_lib_free_vmalloc_buffer(substream);
164error:
165 mutex_unlock(&oxfw->mutex);
166 return err;
167}
168
169static int pcm_hw_free(struct snd_pcm_substream *substream)
170{
171 struct snd_oxfw *oxfw = substream->private_data;
172
173 mutex_lock(&oxfw->mutex);
174 snd_oxfw_stream_stop_simplex(oxfw);
175 mutex_unlock(&oxfw->mutex);
176
177 return snd_pcm_lib_free_vmalloc_buffer(substream);
178}
179
180static int pcm_prepare(struct snd_pcm_substream *substream)
181{
182 struct snd_oxfw *oxfw = substream->private_data;
183 int err;
184
185 mutex_lock(&oxfw->mutex);
186
187 snd_oxfw_stream_stop_simplex(oxfw);
188
189 err = snd_oxfw_stream_start_simplex(oxfw);
190 if (err < 0)
191 goto end;
192
193 amdtp_stream_pcm_prepare(&oxfw->rx_stream);
194end:
195 mutex_unlock(&oxfw->mutex);
196 return err;
197}
198
199static int pcm_trigger(struct snd_pcm_substream *substream, int cmd)
200{
201 struct snd_oxfw *oxfw = substream->private_data;
202 struct snd_pcm_substream *pcm;
203
204 switch (cmd) {
205 case SNDRV_PCM_TRIGGER_START:
206 pcm = substream;
207 break;
208 case SNDRV_PCM_TRIGGER_STOP:
209 pcm = NULL;
210 break;
211 default:
212 return -EINVAL;
213 }
214 amdtp_stream_pcm_trigger(&oxfw->rx_stream, pcm);
215 return 0;
216}
217
218static snd_pcm_uframes_t pcm_pointer(struct snd_pcm_substream *substream)
219{
220 struct snd_oxfw *oxfw = substream->private_data;
221
222 return amdtp_stream_pcm_pointer(&oxfw->rx_stream);
223}
224
225int snd_oxfw_create_pcm(struct snd_oxfw *oxfw)
226{
227 static struct snd_pcm_ops ops = {
228 .open = pcm_open,
229 .close = pcm_close,
230 .ioctl = snd_pcm_lib_ioctl,
231 .hw_params = pcm_hw_params,
232 .hw_free = pcm_hw_free,
233 .prepare = pcm_prepare,
234 .trigger = pcm_trigger,
235 .pointer = pcm_pointer,
236 .page = snd_pcm_lib_get_vmalloc_page,
237 .mmap = snd_pcm_lib_mmap_vmalloc,
238 };
239 struct snd_pcm *pcm;
240 int err;
241
242 err = snd_pcm_new(oxfw->card, oxfw->card->driver, 0, 1, 0, &pcm);
243 if (err < 0)
244 return err;
245 pcm->private_data = oxfw;
246 strcpy(pcm->name, oxfw->card->shortname);
247 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ops);
248 return 0;
249}
diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c
index 40556677ea07..24bb6dff23cc 100644
--- a/sound/firewire/oxfw/oxfw.c
+++ b/sound/firewire/oxfw/oxfw.c
@@ -25,244 +25,6 @@ MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
25MODULE_LICENSE("GPL v2"); 25MODULE_LICENSE("GPL v2");
26MODULE_ALIAS("snd-firewire-speakers"); 26MODULE_ALIAS("snd-firewire-speakers");
27 27
28static int firewave_rate_constraint(struct snd_pcm_hw_params *params,
29 struct snd_pcm_hw_rule *rule)
30{
31 static unsigned int stereo_rates[] = { 48000, 96000 };
32 struct snd_interval *channels =
33 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
34 struct snd_interval *rate =
35 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
36
37 /* two channels work only at 48/96 kHz */
38 if (snd_interval_max(channels) < 6)
39 return snd_interval_list(rate, 2, stereo_rates, 0);
40 return 0;
41}
42
43static int firewave_channels_constraint(struct snd_pcm_hw_params *params,
44 struct snd_pcm_hw_rule *rule)
45{
46 static const struct snd_interval all_channels = { .min = 6, .max = 6 };
47 struct snd_interval *rate =
48 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
49 struct snd_interval *channels =
50 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
51
52 /* 32/44.1 kHz work only with all six channels */
53 if (snd_interval_max(rate) < 48000)
54 return snd_interval_refine(channels, &all_channels);
55 return 0;
56}
57
58static int firewave_constraints(struct snd_pcm_runtime *runtime)
59{
60 static unsigned int channels_list[] = { 2, 6 };
61 static struct snd_pcm_hw_constraint_list channels_list_constraint = {
62 .count = 2,
63 .list = channels_list,
64 };
65 int err;
66
67 runtime->hw.rates = SNDRV_PCM_RATE_32000 |
68 SNDRV_PCM_RATE_44100 |
69 SNDRV_PCM_RATE_48000 |
70 SNDRV_PCM_RATE_96000;
71 runtime->hw.channels_max = 6;
72
73 err = snd_pcm_hw_constraint_list(runtime, 0,
74 SNDRV_PCM_HW_PARAM_CHANNELS,
75 &channels_list_constraint);
76 if (err < 0)
77 return err;
78 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
79 firewave_rate_constraint, NULL,
80 SNDRV_PCM_HW_PARAM_CHANNELS, -1);
81 if (err < 0)
82 return err;
83 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
84 firewave_channels_constraint, NULL,
85 SNDRV_PCM_HW_PARAM_RATE, -1);
86 if (err < 0)
87 return err;
88
89 return 0;
90}
91
92static int lacie_speakers_constraints(struct snd_pcm_runtime *runtime)
93{
94 runtime->hw.rates = SNDRV_PCM_RATE_32000 |
95 SNDRV_PCM_RATE_44100 |
96 SNDRV_PCM_RATE_48000 |
97 SNDRV_PCM_RATE_88200 |
98 SNDRV_PCM_RATE_96000;
99
100 return 0;
101}
102
103static int oxfw_open(struct snd_pcm_substream *substream)
104{
105 static const struct snd_pcm_hardware hardware = {
106 .info = SNDRV_PCM_INFO_MMAP |
107 SNDRV_PCM_INFO_MMAP_VALID |
108 SNDRV_PCM_INFO_BATCH |
109 SNDRV_PCM_INFO_INTERLEAVED |
110 SNDRV_PCM_INFO_BLOCK_TRANSFER,
111 .formats = AMDTP_OUT_PCM_FORMAT_BITS,
112 .channels_min = 2,
113 .channels_max = 2,
114 .buffer_bytes_max = 4 * 1024 * 1024,
115 .period_bytes_min = 1,
116 .period_bytes_max = UINT_MAX,
117 .periods_min = 1,
118 .periods_max = UINT_MAX,
119 };
120 struct snd_oxfw *oxfw = substream->private_data;
121 struct snd_pcm_runtime *runtime = substream->runtime;
122 int err;
123
124 runtime->hw = hardware;
125
126 err = oxfw->device_info->pcm_constraints(runtime);
127 if (err < 0)
128 return err;
129 err = snd_pcm_limit_hw_rates(runtime);
130 if (err < 0)
131 return err;
132
133 err = amdtp_stream_add_pcm_hw_constraints(&oxfw->rx_stream, runtime);
134 if (err < 0)
135 return err;
136
137 return 0;
138}
139
140static int oxfw_close(struct snd_pcm_substream *substream)
141{
142 return 0;
143}
144
145static int oxfw_hw_params(struct snd_pcm_substream *substream,
146 struct snd_pcm_hw_params *hw_params)
147{
148 struct snd_oxfw *oxfw = substream->private_data;
149 int err;
150
151 mutex_lock(&oxfw->mutex);
152
153 snd_oxfw_stream_stop_simplex(oxfw);
154
155 err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
156 params_buffer_bytes(hw_params));
157 if (err < 0)
158 goto error;
159
160 amdtp_stream_set_parameters(&oxfw->rx_stream,
161 params_rate(hw_params),
162 params_channels(hw_params),
163 0);
164
165 amdtp_stream_set_pcm_format(&oxfw->rx_stream,
166 params_format(hw_params));
167
168 err = avc_general_set_sig_fmt(oxfw->unit, params_rate(hw_params),
169 AVC_GENERAL_PLUG_DIR_IN, 0);
170 if (err < 0) {
171 dev_err(&oxfw->unit->device, "failed to set sample rate\n");
172 goto err_buffer;
173 }
174
175 return 0;
176
177err_buffer:
178 snd_pcm_lib_free_vmalloc_buffer(substream);
179error:
180 mutex_unlock(&oxfw->mutex);
181 return err;
182}
183
184static int oxfw_hw_free(struct snd_pcm_substream *substream)
185{
186 struct snd_oxfw *oxfw = substream->private_data;
187
188 mutex_lock(&oxfw->mutex);
189 snd_oxfw_stream_stop_simplex(oxfw);
190 mutex_unlock(&oxfw->mutex);
191
192 return snd_pcm_lib_free_vmalloc_buffer(substream);
193}
194
195static int oxfw_prepare(struct snd_pcm_substream *substream)
196{
197 struct snd_oxfw *oxfw = substream->private_data;
198 int err;
199
200 mutex_lock(&oxfw->mutex);
201
202 snd_oxfw_stream_stop_simplex(oxfw);
203
204 err = snd_oxfw_stream_start_simplex(oxfw);
205 if (err < 0)
206 goto end;
207
208 amdtp_stream_pcm_prepare(&oxfw->rx_stream);
209end:
210 mutex_unlock(&oxfw->mutex);
211 return err;
212}
213
214static int oxfw_trigger(struct snd_pcm_substream *substream, int cmd)
215{
216 struct snd_oxfw *oxfw = substream->private_data;
217 struct snd_pcm_substream *pcm;
218
219 switch (cmd) {
220 case SNDRV_PCM_TRIGGER_START:
221 pcm = substream;
222 break;
223 case SNDRV_PCM_TRIGGER_STOP:
224 pcm = NULL;
225 break;
226 default:
227 return -EINVAL;
228 }
229 amdtp_stream_pcm_trigger(&oxfw->rx_stream, pcm);
230 return 0;
231}
232
233static snd_pcm_uframes_t oxfw_pointer(struct snd_pcm_substream *substream)
234{
235 struct snd_oxfw *oxfw = substream->private_data;
236
237 return amdtp_stream_pcm_pointer(&oxfw->rx_stream);
238}
239
240static int oxfw_create_pcm(struct snd_oxfw *oxfw)
241{
242 static struct snd_pcm_ops ops = {
243 .open = oxfw_open,
244 .close = oxfw_close,
245 .ioctl = snd_pcm_lib_ioctl,
246 .hw_params = oxfw_hw_params,
247 .hw_free = oxfw_hw_free,
248 .prepare = oxfw_prepare,
249 .trigger = oxfw_trigger,
250 .pointer = oxfw_pointer,
251 .page = snd_pcm_lib_get_vmalloc_page,
252 .mmap = snd_pcm_lib_mmap_vmalloc,
253 };
254 struct snd_pcm *pcm;
255 int err;
256
257 err = snd_pcm_new(oxfw->card, "OXFW", 0, 1, 0, &pcm);
258 if (err < 0)
259 return err;
260 pcm->private_data = oxfw;
261 strcpy(pcm->name, oxfw->device_info->short_name);
262 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ops);
263 return 0;
264}
265
266enum control_action { CTL_READ, CTL_WRITE }; 28enum control_action { CTL_READ, CTL_WRITE };
267enum control_attribute { 29enum control_attribute {
268 CTL_MIN = 0x02, 30 CTL_MIN = 0x02,
@@ -587,7 +349,7 @@ static int oxfw_probe(struct fw_unit *unit,
587 dev_name(&unit->device), 100 << fw_dev->max_speed); 349 dev_name(&unit->device), 100 << fw_dev->max_speed);
588 strcpy(card->mixername, "OXFW"); 350 strcpy(card->mixername, "OXFW");
589 351
590 err = oxfw_create_pcm(oxfw); 352 err = snd_oxfw_create_pcm(oxfw);
591 if (err < 0) 353 if (err < 0)
592 goto error; 354 goto error;
593 355
diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h
index e5836e02b48c..1196db8a6300 100644
--- a/sound/firewire/oxfw/oxfw.h
+++ b/sound/firewire/oxfw/oxfw.h
@@ -54,3 +54,7 @@ int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw);
54void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw); 54void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw);
55void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw); 55void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw);
56void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw); 56void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw);
57
58int firewave_constraints(struct snd_pcm_runtime *runtime);
59int lacie_speakers_constraints(struct snd_pcm_runtime *runtime);
60int snd_oxfw_create_pcm(struct snd_oxfw *oxfw);