1 /* 2 * dice_pcm.c - a part of driver for DICE based devices 3 * 4 * Copyright (c) Clemens Ladisch <clemens@ladisch.de> 5 * Copyright (c) 2014 Takashi Sakamoto <o-takashi@sakamocchi.jp> 6 * 7 * Licensed under the terms of the GNU General Public License, version 2. 8 */ 9 10 #include "dice.h" 11 12 static int limit_channels_and_rates(struct snd_dice *dice, 13 struct snd_pcm_runtime *runtime, 14 enum amdtp_stream_direction dir, 15 unsigned int index, unsigned int size) 16 { 17 struct snd_pcm_hardware *hw = &runtime->hw; 18 struct amdtp_stream *stream; 19 unsigned int rate; 20 __be32 reg; 21 int err; 22 23 /* 24 * Retrieve current Multi Bit Linear Audio data channel and limit to 25 * it. 26 */ 27 if (dir == AMDTP_IN_STREAM) { 28 stream = &dice->tx_stream[index]; 29 err = snd_dice_transaction_read_tx(dice, 30 size * index + TX_NUMBER_AUDIO, 31 ®, sizeof(reg)); 32 } else { 33 stream = &dice->rx_stream[index]; 34 err = snd_dice_transaction_read_rx(dice, 35 size * index + RX_NUMBER_AUDIO, 36 ®, sizeof(reg)); 37 } 38 if (err < 0) 39 return err; 40 41 hw->channels_min = hw->channels_max = be32_to_cpu(reg); 42 43 /* Retrieve current sampling transfer frequency and limit to it. */ 44 err = snd_dice_transaction_get_rate(dice, &rate); 45 if (err < 0) 46 return err; 47 48 hw->rates = snd_pcm_rate_to_rate_bit(rate); 49 snd_pcm_limit_hw_rates(runtime); 50 51 return 0; 52 } 53 54 static void limit_period_and_buffer(struct snd_pcm_hardware *hw) 55 { 56 hw->periods_min = 2; /* SNDRV_PCM_INFO_BATCH */ 57 hw->periods_max = UINT_MAX; 58 59 hw->period_bytes_min = 4 * hw->channels_max; /* byte for a frame */ 60 61 /* Just to prevent from allocating much pages. */ 62 hw->period_bytes_max = hw->period_bytes_min * 2048; 63 hw->buffer_bytes_max = hw->period_bytes_max * hw->periods_min; 64 } 65 66 static int init_hw_info(struct snd_dice *dice, 67 struct snd_pcm_substream *substream) 68 { 69 struct snd_pcm_runtime *runtime = substream->runtime; 70 struct snd_pcm_hardware *hw = &runtime->hw; 71 enum amdtp_stream_direction dir; 72 struct amdtp_stream *stream; 73 __be32 reg[2]; 74 unsigned int count, size; 75 int err; 76 77 hw->info = SNDRV_PCM_INFO_MMAP | 78 SNDRV_PCM_INFO_MMAP_VALID | 79 SNDRV_PCM_INFO_BATCH | 80 SNDRV_PCM_INFO_INTERLEAVED | 81 SNDRV_PCM_INFO_JOINT_DUPLEX | 82 SNDRV_PCM_INFO_BLOCK_TRANSFER; 83 84 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 85 hw->formats = AM824_IN_PCM_FORMAT_BITS; 86 dir = AMDTP_IN_STREAM; 87 stream = &dice->tx_stream[substream->pcm->device]; 88 err = snd_dice_transaction_read_tx(dice, TX_NUMBER, reg, 89 sizeof(reg)); 90 } else { 91 hw->formats = AM824_OUT_PCM_FORMAT_BITS; 92 dir = AMDTP_OUT_STREAM; 93 stream = &dice->rx_stream[substream->pcm->device]; 94 err = snd_dice_transaction_read_rx(dice, RX_NUMBER, reg, 95 sizeof(reg)); 96 } 97 98 if (err < 0) 99 return err; 100 101 count = min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS); 102 if (substream->pcm->device >= count) 103 return -ENXIO; 104 105 size = be32_to_cpu(reg[1]) * 4; 106 err = limit_channels_and_rates(dice, substream->runtime, dir, 107 substream->pcm->device, size); 108 if (err < 0) 109 return err; 110 limit_period_and_buffer(hw); 111 112 return amdtp_am824_add_pcm_hw_constraints(stream, runtime); 113 } 114 115 static int pcm_open(struct snd_pcm_substream *substream) 116 { 117 struct snd_dice *dice = substream->private_data; 118 int err; 119 120 err = snd_dice_stream_lock_try(dice); 121 if (err < 0) 122 goto end; 123 124 err = init_hw_info(dice, substream); 125 if (err < 0) 126 goto err_locked; 127 128 snd_pcm_set_sync(substream); 129 end: 130 return err; 131 err_locked: 132 snd_dice_stream_lock_release(dice); 133 return err; 134 } 135 136 static int pcm_close(struct snd_pcm_substream *substream) 137 { 138 struct snd_dice *dice = substream->private_data; 139 140 snd_dice_stream_lock_release(dice); 141 142 return 0; 143 } 144 145 static int capture_hw_params(struct snd_pcm_substream *substream, 146 struct snd_pcm_hw_params *hw_params) 147 { 148 struct snd_dice *dice = substream->private_data; 149 struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device]; 150 int err; 151 152 err = snd_pcm_lib_alloc_vmalloc_buffer(substream, 153 params_buffer_bytes(hw_params)); 154 if (err < 0) 155 return err; 156 157 if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { 158 mutex_lock(&dice->mutex); 159 dice->substreams_counter++; 160 mutex_unlock(&dice->mutex); 161 } 162 163 amdtp_am824_set_pcm_format(stream, params_format(hw_params)); 164 165 return 0; 166 } 167 static int playback_hw_params(struct snd_pcm_substream *substream, 168 struct snd_pcm_hw_params *hw_params) 169 { 170 struct snd_dice *dice = substream->private_data; 171 struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device]; 172 int err; 173 174 err = snd_pcm_lib_alloc_vmalloc_buffer(substream, 175 params_buffer_bytes(hw_params)); 176 if (err < 0) 177 return err; 178 179 if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { 180 mutex_lock(&dice->mutex); 181 dice->substreams_counter++; 182 mutex_unlock(&dice->mutex); 183 } 184 185 amdtp_am824_set_pcm_format(stream, params_format(hw_params)); 186 187 return 0; 188 } 189 190 static int capture_hw_free(struct snd_pcm_substream *substream) 191 { 192 struct snd_dice *dice = substream->private_data; 193 194 mutex_lock(&dice->mutex); 195 196 if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) 197 dice->substreams_counter--; 198 199 snd_dice_stream_stop_duplex(dice); 200 201 mutex_unlock(&dice->mutex); 202 203 return snd_pcm_lib_free_vmalloc_buffer(substream); 204 } 205 206 static int playback_hw_free(struct snd_pcm_substream *substream) 207 { 208 struct snd_dice *dice = substream->private_data; 209 210 mutex_lock(&dice->mutex); 211 212 if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) 213 dice->substreams_counter--; 214 215 snd_dice_stream_stop_duplex(dice); 216 217 mutex_unlock(&dice->mutex); 218 219 return snd_pcm_lib_free_vmalloc_buffer(substream); 220 } 221 222 static int capture_prepare(struct snd_pcm_substream *substream) 223 { 224 struct snd_dice *dice = substream->private_data; 225 struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device]; 226 int err; 227 228 mutex_lock(&dice->mutex); 229 err = snd_dice_stream_start_duplex(dice, substream->runtime->rate); 230 mutex_unlock(&dice->mutex); 231 if (err >= 0) 232 amdtp_stream_pcm_prepare(stream); 233 234 return 0; 235 } 236 static int playback_prepare(struct snd_pcm_substream *substream) 237 { 238 struct snd_dice *dice = substream->private_data; 239 struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device]; 240 int err; 241 242 mutex_lock(&dice->mutex); 243 err = snd_dice_stream_start_duplex(dice, substream->runtime->rate); 244 mutex_unlock(&dice->mutex); 245 if (err >= 0) 246 amdtp_stream_pcm_prepare(stream); 247 248 return err; 249 } 250 251 static int capture_trigger(struct snd_pcm_substream *substream, int cmd) 252 { 253 struct snd_dice *dice = substream->private_data; 254 struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device]; 255 256 switch (cmd) { 257 case SNDRV_PCM_TRIGGER_START: 258 amdtp_stream_pcm_trigger(stream, substream); 259 break; 260 case SNDRV_PCM_TRIGGER_STOP: 261 amdtp_stream_pcm_trigger(stream, NULL); 262 break; 263 default: 264 return -EINVAL; 265 } 266 267 return 0; 268 } 269 static int playback_trigger(struct snd_pcm_substream *substream, int cmd) 270 { 271 struct snd_dice *dice = substream->private_data; 272 struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device]; 273 274 switch (cmd) { 275 case SNDRV_PCM_TRIGGER_START: 276 amdtp_stream_pcm_trigger(stream, substream); 277 break; 278 case SNDRV_PCM_TRIGGER_STOP: 279 amdtp_stream_pcm_trigger(stream, NULL); 280 break; 281 default: 282 return -EINVAL; 283 } 284 285 return 0; 286 } 287 288 static snd_pcm_uframes_t capture_pointer(struct snd_pcm_substream *substream) 289 { 290 struct snd_dice *dice = substream->private_data; 291 struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device]; 292 293 return amdtp_stream_pcm_pointer(stream); 294 } 295 static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream) 296 { 297 struct snd_dice *dice = substream->private_data; 298 struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device]; 299 300 return amdtp_stream_pcm_pointer(stream); 301 } 302 303 int snd_dice_create_pcm(struct snd_dice *dice) 304 { 305 static const struct snd_pcm_ops capture_ops = { 306 .open = pcm_open, 307 .close = pcm_close, 308 .ioctl = snd_pcm_lib_ioctl, 309 .hw_params = capture_hw_params, 310 .hw_free = capture_hw_free, 311 .prepare = capture_prepare, 312 .trigger = capture_trigger, 313 .pointer = capture_pointer, 314 .page = snd_pcm_lib_get_vmalloc_page, 315 .mmap = snd_pcm_lib_mmap_vmalloc, 316 }; 317 static const struct snd_pcm_ops playback_ops = { 318 .open = pcm_open, 319 .close = pcm_close, 320 .ioctl = snd_pcm_lib_ioctl, 321 .hw_params = playback_hw_params, 322 .hw_free = playback_hw_free, 323 .prepare = playback_prepare, 324 .trigger = playback_trigger, 325 .pointer = playback_pointer, 326 .page = snd_pcm_lib_get_vmalloc_page, 327 .mmap = snd_pcm_lib_mmap_vmalloc, 328 }; 329 __be32 reg; 330 struct snd_pcm *pcm; 331 unsigned int i, max_capture, max_playback, capture, playback; 332 int err; 333 334 /* Check whether PCM substreams are required. */ 335 if (dice->force_two_pcms) { 336 max_capture = max_playback = 2; 337 } else { 338 max_capture = max_playback = 0; 339 err = snd_dice_transaction_read_tx(dice, TX_NUMBER, ®, 340 sizeof(reg)); 341 if (err < 0) 342 return err; 343 max_capture = min_t(unsigned int, be32_to_cpu(reg), MAX_STREAMS); 344 345 err = snd_dice_transaction_read_rx(dice, RX_NUMBER, ®, 346 sizeof(reg)); 347 if (err < 0) 348 return err; 349 max_playback = min_t(unsigned int, be32_to_cpu(reg), MAX_STREAMS); 350 } 351 352 for (i = 0; i < MAX_STREAMS; i++) { 353 capture = playback = 0; 354 if (i < max_capture) 355 capture = 1; 356 if (i < max_playback) 357 playback = 1; 358 if (capture == 0 && playback == 0) 359 break; 360 361 err = snd_pcm_new(dice->card, "DICE", i, playback, capture, 362 &pcm); 363 if (err < 0) 364 return err; 365 pcm->private_data = dice; 366 strcpy(pcm->name, dice->card->shortname); 367 368 if (capture > 0) 369 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, 370 &capture_ops); 371 372 if (playback > 0) 373 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, 374 &playback_ops); 375 } 376 377 return 0; 378 } 379