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 int init_hw_info(struct snd_dice *dice, 55 struct snd_pcm_substream *substream) 56 { 57 struct snd_pcm_runtime *runtime = substream->runtime; 58 struct snd_pcm_hardware *hw = &runtime->hw; 59 enum amdtp_stream_direction dir; 60 struct amdtp_stream *stream; 61 __be32 reg[2]; 62 unsigned int count, size; 63 int err; 64 65 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 66 hw->formats = AM824_IN_PCM_FORMAT_BITS; 67 dir = AMDTP_IN_STREAM; 68 stream = &dice->tx_stream[substream->pcm->device]; 69 err = snd_dice_transaction_read_tx(dice, TX_NUMBER, reg, 70 sizeof(reg)); 71 } else { 72 hw->formats = AM824_OUT_PCM_FORMAT_BITS; 73 dir = AMDTP_OUT_STREAM; 74 stream = &dice->rx_stream[substream->pcm->device]; 75 err = snd_dice_transaction_read_rx(dice, RX_NUMBER, reg, 76 sizeof(reg)); 77 } 78 79 if (err < 0) 80 return err; 81 82 count = min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS); 83 if (substream->pcm->device >= count) 84 return -ENXIO; 85 86 size = be32_to_cpu(reg[1]) * 4; 87 err = limit_channels_and_rates(dice, substream->runtime, dir, 88 substream->pcm->device, size); 89 if (err < 0) 90 return err; 91 92 return amdtp_am824_add_pcm_hw_constraints(stream, runtime); 93 } 94 95 static int pcm_open(struct snd_pcm_substream *substream) 96 { 97 struct snd_dice *dice = substream->private_data; 98 int err; 99 100 err = snd_dice_stream_lock_try(dice); 101 if (err < 0) 102 goto end; 103 104 err = init_hw_info(dice, substream); 105 if (err < 0) 106 goto err_locked; 107 108 snd_pcm_set_sync(substream); 109 end: 110 return err; 111 err_locked: 112 snd_dice_stream_lock_release(dice); 113 return err; 114 } 115 116 static int pcm_close(struct snd_pcm_substream *substream) 117 { 118 struct snd_dice *dice = substream->private_data; 119 120 snd_dice_stream_lock_release(dice); 121 122 return 0; 123 } 124 125 static int capture_hw_params(struct snd_pcm_substream *substream, 126 struct snd_pcm_hw_params *hw_params) 127 { 128 struct snd_dice *dice = substream->private_data; 129 int err; 130 131 err = snd_pcm_lib_alloc_vmalloc_buffer(substream, 132 params_buffer_bytes(hw_params)); 133 if (err < 0) 134 return err; 135 136 if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { 137 mutex_lock(&dice->mutex); 138 dice->substreams_counter++; 139 mutex_unlock(&dice->mutex); 140 } 141 142 return 0; 143 } 144 static int playback_hw_params(struct snd_pcm_substream *substream, 145 struct snd_pcm_hw_params *hw_params) 146 { 147 struct snd_dice *dice = substream->private_data; 148 int err; 149 150 err = snd_pcm_lib_alloc_vmalloc_buffer(substream, 151 params_buffer_bytes(hw_params)); 152 if (err < 0) 153 return err; 154 155 if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { 156 mutex_lock(&dice->mutex); 157 dice->substreams_counter++; 158 mutex_unlock(&dice->mutex); 159 } 160 161 return 0; 162 } 163 164 static int capture_hw_free(struct snd_pcm_substream *substream) 165 { 166 struct snd_dice *dice = substream->private_data; 167 168 mutex_lock(&dice->mutex); 169 170 if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) 171 dice->substreams_counter--; 172 173 snd_dice_stream_stop_duplex(dice); 174 175 mutex_unlock(&dice->mutex); 176 177 return snd_pcm_lib_free_vmalloc_buffer(substream); 178 } 179 180 static int playback_hw_free(struct snd_pcm_substream *substream) 181 { 182 struct snd_dice *dice = substream->private_data; 183 184 mutex_lock(&dice->mutex); 185 186 if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) 187 dice->substreams_counter--; 188 189 snd_dice_stream_stop_duplex(dice); 190 191 mutex_unlock(&dice->mutex); 192 193 return snd_pcm_lib_free_vmalloc_buffer(substream); 194 } 195 196 static int capture_prepare(struct snd_pcm_substream *substream) 197 { 198 struct snd_dice *dice = substream->private_data; 199 struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device]; 200 int err; 201 202 mutex_lock(&dice->mutex); 203 err = snd_dice_stream_start_duplex(dice, substream->runtime->rate); 204 mutex_unlock(&dice->mutex); 205 if (err >= 0) 206 amdtp_stream_pcm_prepare(stream); 207 208 return 0; 209 } 210 static int playback_prepare(struct snd_pcm_substream *substream) 211 { 212 struct snd_dice *dice = substream->private_data; 213 struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device]; 214 int err; 215 216 mutex_lock(&dice->mutex); 217 err = snd_dice_stream_start_duplex(dice, substream->runtime->rate); 218 mutex_unlock(&dice->mutex); 219 if (err >= 0) 220 amdtp_stream_pcm_prepare(stream); 221 222 return err; 223 } 224 225 static int capture_trigger(struct snd_pcm_substream *substream, int cmd) 226 { 227 struct snd_dice *dice = substream->private_data; 228 struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device]; 229 230 switch (cmd) { 231 case SNDRV_PCM_TRIGGER_START: 232 amdtp_stream_pcm_trigger(stream, substream); 233 break; 234 case SNDRV_PCM_TRIGGER_STOP: 235 amdtp_stream_pcm_trigger(stream, NULL); 236 break; 237 default: 238 return -EINVAL; 239 } 240 241 return 0; 242 } 243 static int playback_trigger(struct snd_pcm_substream *substream, int cmd) 244 { 245 struct snd_dice *dice = substream->private_data; 246 struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device]; 247 248 switch (cmd) { 249 case SNDRV_PCM_TRIGGER_START: 250 amdtp_stream_pcm_trigger(stream, substream); 251 break; 252 case SNDRV_PCM_TRIGGER_STOP: 253 amdtp_stream_pcm_trigger(stream, NULL); 254 break; 255 default: 256 return -EINVAL; 257 } 258 259 return 0; 260 } 261 262 static snd_pcm_uframes_t capture_pointer(struct snd_pcm_substream *substream) 263 { 264 struct snd_dice *dice = substream->private_data; 265 struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device]; 266 267 return amdtp_stream_pcm_pointer(stream); 268 } 269 static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream) 270 { 271 struct snd_dice *dice = substream->private_data; 272 struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device]; 273 274 return amdtp_stream_pcm_pointer(stream); 275 } 276 277 static int capture_ack(struct snd_pcm_substream *substream) 278 { 279 struct snd_dice *dice = substream->private_data; 280 struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device]; 281 282 return amdtp_stream_pcm_ack(stream); 283 } 284 285 static int playback_ack(struct snd_pcm_substream *substream) 286 { 287 struct snd_dice *dice = substream->private_data; 288 struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device]; 289 290 return amdtp_stream_pcm_ack(stream); 291 } 292 293 int snd_dice_create_pcm(struct snd_dice *dice) 294 { 295 static const struct snd_pcm_ops capture_ops = { 296 .open = pcm_open, 297 .close = pcm_close, 298 .ioctl = snd_pcm_lib_ioctl, 299 .hw_params = capture_hw_params, 300 .hw_free = capture_hw_free, 301 .prepare = capture_prepare, 302 .trigger = capture_trigger, 303 .pointer = capture_pointer, 304 .ack = capture_ack, 305 .page = snd_pcm_lib_get_vmalloc_page, 306 .mmap = snd_pcm_lib_mmap_vmalloc, 307 }; 308 static const struct snd_pcm_ops playback_ops = { 309 .open = pcm_open, 310 .close = pcm_close, 311 .ioctl = snd_pcm_lib_ioctl, 312 .hw_params = playback_hw_params, 313 .hw_free = playback_hw_free, 314 .prepare = playback_prepare, 315 .trigger = playback_trigger, 316 .pointer = playback_pointer, 317 .ack = playback_ack, 318 .page = snd_pcm_lib_get_vmalloc_page, 319 .mmap = snd_pcm_lib_mmap_vmalloc, 320 }; 321 __be32 reg; 322 struct snd_pcm *pcm; 323 unsigned int i, max_capture, max_playback, capture, playback; 324 int err; 325 326 /* Check whether PCM substreams are required. */ 327 if (dice->force_two_pcms) { 328 max_capture = max_playback = 2; 329 } else { 330 max_capture = max_playback = 0; 331 err = snd_dice_transaction_read_tx(dice, TX_NUMBER, ®, 332 sizeof(reg)); 333 if (err < 0) 334 return err; 335 max_capture = min_t(unsigned int, be32_to_cpu(reg), MAX_STREAMS); 336 337 err = snd_dice_transaction_read_rx(dice, RX_NUMBER, ®, 338 sizeof(reg)); 339 if (err < 0) 340 return err; 341 max_playback = min_t(unsigned int, be32_to_cpu(reg), MAX_STREAMS); 342 } 343 344 for (i = 0; i < MAX_STREAMS; i++) { 345 capture = playback = 0; 346 if (i < max_capture) 347 capture = 1; 348 if (i < max_playback) 349 playback = 1; 350 if (capture == 0 && playback == 0) 351 break; 352 353 err = snd_pcm_new(dice->card, "DICE", i, playback, capture, 354 &pcm); 355 if (err < 0) 356 return err; 357 pcm->private_data = dice; 358 strcpy(pcm->name, dice->card->shortname); 359 360 if (capture > 0) 361 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, 362 &capture_ops); 363 364 if (playback > 0) 365 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, 366 &playback_ops); 367 } 368 369 return 0; 370 } 371