aboutsummaryrefslogtreecommitdiffstats
path: root/sound/firewire
diff options
context:
space:
mode:
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>2014-11-28 10:59:18 -0500
committerTakashi Iwai <tiwai@suse.de>2014-11-29 14:17:06 -0500
commit2c2416c83e7345fc51af49132c40ec7d337d4132 (patch)
tree8e7429e9c5b4abd80a0a097e4ef0e2804cd17510 /sound/firewire
parent04d426a039691bf114997a8af877682fdffcebd7 (diff)
ALSA: dice: Add new functions for constraints of PCM parameters
This commit adds a new functions and some arrangement for PCM restriction. This arrangement is due to the number of channels which each Dice device has. I note that minimum number for period becomes 2, instead of 1 because its PCM functionality has SNDRV_PCM_INFO_BATCH, this means that the driver uses double (or more) buffering so the minimum number for period should be 2. 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/dice/dice-pcm.c109
1 files changed, 65 insertions, 44 deletions
diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c
index deacb537eb81..2e531bd30e28 100644
--- a/sound/firewire/dice/dice-pcm.c
+++ b/sound/firewire/dice/dice-pcm.c
@@ -67,71 +67,92 @@ static int dice_channels_constraint(struct snd_pcm_hw_params *params,
67 return snd_interval_refine(c, &channels); 67 return snd_interval_refine(c, &channels);
68} 68}
69 69
70 70static void limit_channels_and_rates(struct snd_dice *dice,
71static int pcm_open(struct snd_pcm_substream *substream) 71 struct snd_pcm_runtime *runtime,
72 unsigned int *pcm_channels)
72{ 73{
73 static const struct snd_pcm_hardware hardware = { 74 struct snd_pcm_hardware *hw = &runtime->hw;
74 .info = SNDRV_PCM_INFO_MMAP | 75 unsigned int i, rate, mode;
75 SNDRV_PCM_INFO_MMAP_VALID |
76 SNDRV_PCM_INFO_BATCH |
77 SNDRV_PCM_INFO_INTERLEAVED |
78 SNDRV_PCM_INFO_BLOCK_TRANSFER,
79 .formats = AMDTP_OUT_PCM_FORMAT_BITS,
80 .channels_min = UINT_MAX,
81 .channels_max = 0,
82 .buffer_bytes_max = 16 * 1024 * 1024,
83 .period_bytes_min = 1,
84 .period_bytes_max = UINT_MAX,
85 .periods_min = 1,
86 .periods_max = UINT_MAX,
87 };
88 struct snd_dice *dice = substream->private_data;
89 struct snd_pcm_runtime *runtime = substream->runtime;
90 unsigned int i;
91 int err;
92 76
93 err = snd_dice_stream_lock_try(dice); 77 hw->channels_min = UINT_MAX;
94 if (err < 0) 78 hw->channels_max = 0;
95 goto error;
96
97 runtime->hw = hardware;
98 79
99 for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) { 80 for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) {
100 if (dice->clock_caps & (1 << i)) 81 rate = snd_dice_rates[i];
101 runtime->hw.rates |= 82 if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0)
102 snd_pcm_rate_to_rate_bit(snd_dice_rates[i]); 83 continue;
84 hw->rates |= snd_pcm_rate_to_rate_bit(rate);
85
86 if (pcm_channels[mode] == 0)
87 continue;
88 hw->channels_min = min(hw->channels_min, pcm_channels[mode]);
89 hw->channels_max = max(hw->channels_max, pcm_channels[mode]);
103 } 90 }
91
104 snd_pcm_limit_hw_rates(runtime); 92 snd_pcm_limit_hw_rates(runtime);
93}
105 94
106 for (i = 0; i < 3; ++i) { 95static void limit_period_and_buffer(struct snd_pcm_hardware *hw)
107 if (dice->rx_channels[i]) { 96{
108 runtime->hw.channels_min = min(runtime->hw.channels_min, 97 hw->periods_min = 2; /* SNDRV_PCM_INFO_BATCH */
109 dice->rx_channels[i]); 98 hw->periods_max = UINT_MAX;
110 runtime->hw.channels_max = max(runtime->hw.channels_max, 99
111 dice->rx_channels[i]); 100 hw->period_bytes_min = 4 * hw->channels_max; /* byte for a frame */
112 } 101
113 } 102 /* Just to prevent from allocating much pages. */
103 hw->period_bytes_max = hw->period_bytes_min * 2048;
104 hw->buffer_bytes_max = hw->period_bytes_max * hw->periods_min;
105}
106
107static int init_hw_info(struct snd_dice *dice,
108 struct snd_pcm_substream *substream)
109{
110 struct snd_pcm_runtime *runtime = substream->runtime;
111 struct snd_pcm_hardware *hw = &runtime->hw;
112 int err;
113
114 hw->info = SNDRV_PCM_INFO_MMAP |
115 SNDRV_PCM_INFO_MMAP_VALID |
116 SNDRV_PCM_INFO_BATCH |
117 SNDRV_PCM_INFO_INTERLEAVED |
118 SNDRV_PCM_INFO_BLOCK_TRANSFER;
119 hw->formats = AMDTP_OUT_PCM_FORMAT_BITS;
120
121 limit_channels_and_rates(dice, runtime, dice->rx_channels);
122 limit_period_and_buffer(hw);
114 123
115 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 124 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
116 dice_rate_constraint, dice, 125 dice_rate_constraint, dice,
117 SNDRV_PCM_HW_PARAM_CHANNELS, -1); 126 SNDRV_PCM_HW_PARAM_CHANNELS, -1);
118 if (err < 0) 127 if (err < 0)
119 goto err_lock; 128 goto end;
120 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 129 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
121 dice_channels_constraint, dice, 130 dice_channels_constraint, dice,
122 SNDRV_PCM_HW_PARAM_RATE, -1); 131 SNDRV_PCM_HW_PARAM_RATE, -1);
123 if (err < 0) 132 if (err < 0)
124 goto err_lock; 133 goto end;
125 134
126 err = amdtp_stream_add_pcm_hw_constraints(&dice->rx_stream, runtime); 135 err = amdtp_stream_add_pcm_hw_constraints(&dice->rx_stream, runtime);
127 if (err < 0) 136end:
128 goto err_lock; 137 return err;
138}
129 139
130 return 0; 140static int pcm_open(struct snd_pcm_substream *substream)
141{
142 struct snd_dice *dice = substream->private_data;
143 int err;
131 144
132err_lock: 145 err = snd_dice_stream_lock_try(dice);
146 if (err < 0)
147 goto end;
148
149 err = init_hw_info(dice, substream);
150 if (err < 0)
151 goto err_locked;
152end:
153 return err;
154err_locked:
133 snd_dice_stream_lock_release(dice); 155 snd_dice_stream_lock_release(dice);
134error:
135 return err; 156 return err;
136} 157}
137 158