1/** 2 * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. 3 * 4 * This source file is released under GPL v2 license (no other versions). 5 * See the COPYING file included in the main directory of this source 6 * distribution for the license terms and conditions. 7 * 8 * @File ctpcm.c 9 * 10 * @Brief 11 * This file contains the definition of the pcm device functions. 12 * 13 * @Author Liu Chun 14 * @Date Apr 2 2008 15 * 16 */ 17 18#include "ctpcm.h" 19#include "cttimer.h" 20#include <linux/slab.h> 21#include <sound/pcm.h> 22 23/* Hardware descriptions for playback */ 24static struct snd_pcm_hardware ct_pcm_playback_hw = { 25 .info = (SNDRV_PCM_INFO_MMAP | 26 SNDRV_PCM_INFO_INTERLEAVED | 27 SNDRV_PCM_INFO_BLOCK_TRANSFER | 28 SNDRV_PCM_INFO_MMAP_VALID | 29 SNDRV_PCM_INFO_PAUSE), 30 .formats = (SNDRV_PCM_FMTBIT_U8 | 31 SNDRV_PCM_FMTBIT_S16_LE | 32 SNDRV_PCM_FMTBIT_S24_3LE | 33 SNDRV_PCM_FMTBIT_S32_LE | 34 SNDRV_PCM_FMTBIT_FLOAT_LE), 35 .rates = (SNDRV_PCM_RATE_CONTINUOUS | 36 SNDRV_PCM_RATE_8000_192000), 37 .rate_min = 8000, 38 .rate_max = 192000, 39 .channels_min = 1, 40 .channels_max = 2, 41 .buffer_bytes_max = (128*1024), 42 .period_bytes_min = (64), 43 .period_bytes_max = (128*1024), 44 .periods_min = 2, 45 .periods_max = 1024, 46 .fifo_size = 0, 47}; 48 49static struct snd_pcm_hardware ct_spdif_passthru_playback_hw = { 50 .info = (SNDRV_PCM_INFO_MMAP | 51 SNDRV_PCM_INFO_INTERLEAVED | 52 SNDRV_PCM_INFO_BLOCK_TRANSFER | 53 SNDRV_PCM_INFO_MMAP_VALID | 54 SNDRV_PCM_INFO_PAUSE), 55 .formats = SNDRV_PCM_FMTBIT_S16_LE, 56 .rates = (SNDRV_PCM_RATE_48000 | 57 SNDRV_PCM_RATE_44100 | 58 SNDRV_PCM_RATE_32000), 59 .rate_min = 32000, 60 .rate_max = 48000, 61 .channels_min = 2, 62 .channels_max = 2, 63 .buffer_bytes_max = (128*1024), 64 .period_bytes_min = (64), 65 .period_bytes_max = (128*1024), 66 .periods_min = 2, 67 .periods_max = 1024, 68 .fifo_size = 0, 69}; 70 71/* Hardware descriptions for capture */ 72static struct snd_pcm_hardware ct_pcm_capture_hw = { 73 .info = (SNDRV_PCM_INFO_MMAP | 74 SNDRV_PCM_INFO_INTERLEAVED | 75 SNDRV_PCM_INFO_BLOCK_TRANSFER | 76 SNDRV_PCM_INFO_PAUSE | 77 SNDRV_PCM_INFO_MMAP_VALID), 78 .formats = (SNDRV_PCM_FMTBIT_U8 | 79 SNDRV_PCM_FMTBIT_S16_LE | 80 SNDRV_PCM_FMTBIT_S24_3LE | 81 SNDRV_PCM_FMTBIT_S32_LE | 82 SNDRV_PCM_FMTBIT_FLOAT_LE), 83 .rates = (SNDRV_PCM_RATE_CONTINUOUS | 84 SNDRV_PCM_RATE_8000_96000), 85 .rate_min = 8000, 86 .rate_max = 96000, 87 .channels_min = 1, 88 .channels_max = 2, 89 .buffer_bytes_max = (128*1024), 90 .period_bytes_min = (384), 91 .period_bytes_max = (64*1024), 92 .periods_min = 2, 93 .periods_max = 1024, 94 .fifo_size = 0, 95}; 96 97static void ct_atc_pcm_interrupt(struct ct_atc_pcm *atc_pcm) 98{ 99 struct ct_atc_pcm *apcm = atc_pcm; 100 101 if (!apcm->substream) 102 return; 103 104 snd_pcm_period_elapsed(apcm->substream); 105} 106 107static void ct_atc_pcm_free_substream(struct snd_pcm_runtime *runtime) 108{ 109 struct ct_atc_pcm *apcm = runtime->private_data; 110 struct ct_atc *atc = snd_pcm_substream_chip(apcm->substream); 111 112 atc->pcm_release_resources(atc, apcm); 113 ct_timer_instance_free(apcm->timer); 114 kfree(apcm); 115 runtime->private_data = NULL; 116} 117 118/* pcm playback operations */ 119static int ct_pcm_playback_open(struct snd_pcm_substream *substream) 120{ 121 struct ct_atc *atc = snd_pcm_substream_chip(substream); 122 struct snd_pcm_runtime *runtime = substream->runtime; 123 struct ct_atc_pcm *apcm; 124 int err; 125 126 apcm = kzalloc(sizeof(*apcm), GFP_KERNEL); 127 if (!apcm) 128 return -ENOMEM; 129 130 apcm->substream = substream; 131 apcm->interrupt = ct_atc_pcm_interrupt; 132 if (IEC958 == substream->pcm->device) { 133 runtime->hw = ct_spdif_passthru_playback_hw; 134 atc->spdif_out_passthru(atc, 1); 135 } else { 136 runtime->hw = ct_pcm_playback_hw; 137 if (FRONT == substream->pcm->device) 138 runtime->hw.channels_max = 8; 139 } 140 141 err = snd_pcm_hw_constraint_integer(runtime, 142 SNDRV_PCM_HW_PARAM_PERIODS); 143 if (err < 0) { 144 kfree(apcm); 145 return err; 146 } 147 err = snd_pcm_hw_constraint_minmax(runtime, 148 SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 149 1024, UINT_MAX); 150 if (err < 0) { 151 kfree(apcm); 152 return err; 153 } 154 155 apcm->timer = ct_timer_instance_new(atc->timer, apcm); 156 if (!apcm->timer) { 157 kfree(apcm); 158 return -ENOMEM; 159 } 160 runtime->private_data = apcm; 161 runtime->private_free = ct_atc_pcm_free_substream; 162 163 return 0; 164} 165 166static int ct_pcm_playback_close(struct snd_pcm_substream *substream) 167{ 168 struct ct_atc *atc = snd_pcm_substream_chip(substream); 169 170 /* TODO: Notify mixer inactive. */ 171 if (IEC958 == substream->pcm->device) 172 atc->spdif_out_passthru(atc, 0); 173 174 /* The ct_atc_pcm object will be freed by runtime->private_free */ 175 176 return 0; 177} 178 179static int ct_pcm_hw_params(struct snd_pcm_substream *substream, 180 struct snd_pcm_hw_params *hw_params) 181{ 182 struct ct_atc *atc = snd_pcm_substream_chip(substream); 183 struct ct_atc_pcm *apcm = substream->runtime->private_data; 184 int err; 185 186 err = snd_pcm_lib_malloc_pages(substream, 187 params_buffer_bytes(hw_params)); 188 if (err < 0) 189 return err; 190 /* clear previous resources */ 191 atc->pcm_release_resources(atc, apcm); 192 return err; 193} 194 195static int ct_pcm_hw_free(struct snd_pcm_substream *substream) 196{ 197 struct ct_atc *atc = snd_pcm_substream_chip(substream); 198 struct ct_atc_pcm *apcm = substream->runtime->private_data; 199 200 /* clear previous resources */ 201 atc->pcm_release_resources(atc, apcm); 202 /* Free snd-allocated pages */ 203 return snd_pcm_lib_free_pages(substream); 204} 205 206 207static int ct_pcm_playback_prepare(struct snd_pcm_substream *substream) 208{ 209 int err; 210 struct ct_atc *atc = snd_pcm_substream_chip(substream); 211 struct snd_pcm_runtime *runtime = substream->runtime; 212 struct ct_atc_pcm *apcm = runtime->private_data; 213 214 if (IEC958 == substream->pcm->device) 215 err = atc->spdif_passthru_playback_prepare(atc, apcm); 216 else 217 err = atc->pcm_playback_prepare(atc, apcm); 218 219 if (err < 0) { 220 dev_err(atc->card->dev, 221 "Preparing pcm playback failed!!!\n"); 222 return err; 223 } 224 225 return 0; 226} 227 228static int 229ct_pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd) 230{ 231 struct ct_atc *atc = snd_pcm_substream_chip(substream); 232 struct snd_pcm_runtime *runtime = substream->runtime; 233 struct ct_atc_pcm *apcm = runtime->private_data; 234 235 switch (cmd) { 236 case SNDRV_PCM_TRIGGER_START: 237 case SNDRV_PCM_TRIGGER_RESUME: 238 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 239 atc->pcm_playback_start(atc, apcm); 240 break; 241 case SNDRV_PCM_TRIGGER_STOP: 242 case SNDRV_PCM_TRIGGER_SUSPEND: 243 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 244 atc->pcm_playback_stop(atc, apcm); 245 break; 246 default: 247 break; 248 } 249 250 return 0; 251} 252 253static snd_pcm_uframes_t 254ct_pcm_playback_pointer(struct snd_pcm_substream *substream) 255{ 256 unsigned long position; 257 struct ct_atc *atc = snd_pcm_substream_chip(substream); 258 struct snd_pcm_runtime *runtime = substream->runtime; 259 struct ct_atc_pcm *apcm = runtime->private_data; 260 261 /* Read out playback position */ 262 position = atc->pcm_playback_position(atc, apcm); 263 position = bytes_to_frames(runtime, position); 264 if (position >= runtime->buffer_size) 265 position = 0; 266 return position; 267} 268 269/* pcm capture operations */ 270static int ct_pcm_capture_open(struct snd_pcm_substream *substream) 271{ 272 struct ct_atc *atc = snd_pcm_substream_chip(substream); 273 struct snd_pcm_runtime *runtime = substream->runtime; 274 struct ct_atc_pcm *apcm; 275 int err; 276 277 apcm = kzalloc(sizeof(*apcm), GFP_KERNEL); 278 if (!apcm) 279 return -ENOMEM; 280 281 apcm->started = 0; 282 apcm->substream = substream; 283 apcm->interrupt = ct_atc_pcm_interrupt; 284 runtime->hw = ct_pcm_capture_hw; 285 runtime->hw.rate_max = atc->rsr * atc->msr; 286 287 err = snd_pcm_hw_constraint_integer(runtime, 288 SNDRV_PCM_HW_PARAM_PERIODS); 289 if (err < 0) { 290 kfree(apcm); 291 return err; 292 } 293 err = snd_pcm_hw_constraint_minmax(runtime, 294 SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 295 1024, UINT_MAX); 296 if (err < 0) { 297 kfree(apcm); 298 return err; 299 } 300 301 apcm->timer = ct_timer_instance_new(atc->timer, apcm); 302 if (!apcm->timer) { 303 kfree(apcm); 304 return -ENOMEM; 305 } 306 runtime->private_data = apcm; 307 runtime->private_free = ct_atc_pcm_free_substream; 308 309 return 0; 310} 311 312static int ct_pcm_capture_close(struct snd_pcm_substream *substream) 313{ 314 /* The ct_atc_pcm object will be freed by runtime->private_free */ 315 /* TODO: Notify mixer inactive. */ 316 return 0; 317} 318 319static int ct_pcm_capture_prepare(struct snd_pcm_substream *substream) 320{ 321 int err; 322 struct ct_atc *atc = snd_pcm_substream_chip(substream); 323 struct snd_pcm_runtime *runtime = substream->runtime; 324 struct ct_atc_pcm *apcm = runtime->private_data; 325 326 err = atc->pcm_capture_prepare(atc, apcm); 327 if (err < 0) { 328 dev_err(atc->card->dev, 329 "Preparing pcm capture failed!!!\n"); 330 return err; 331 } 332 333 return 0; 334} 335 336static int 337ct_pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd) 338{ 339 struct ct_atc *atc = snd_pcm_substream_chip(substream); 340 struct snd_pcm_runtime *runtime = substream->runtime; 341 struct ct_atc_pcm *apcm = runtime->private_data; 342 343 switch (cmd) { 344 case SNDRV_PCM_TRIGGER_START: 345 atc->pcm_capture_start(atc, apcm); 346 break; 347 case SNDRV_PCM_TRIGGER_STOP: 348 atc->pcm_capture_stop(atc, apcm); 349 break; 350 default: 351 atc->pcm_capture_stop(atc, apcm); 352 break; 353 } 354 355 return 0; 356} 357 358static snd_pcm_uframes_t 359ct_pcm_capture_pointer(struct snd_pcm_substream *substream) 360{ 361 unsigned long position; 362 struct ct_atc *atc = snd_pcm_substream_chip(substream); 363 struct snd_pcm_runtime *runtime = substream->runtime; 364 struct ct_atc_pcm *apcm = runtime->private_data; 365 366 /* Read out playback position */ 367 position = atc->pcm_capture_position(atc, apcm); 368 position = bytes_to_frames(runtime, position); 369 if (position >= runtime->buffer_size) 370 position = 0; 371 return position; 372} 373 374/* PCM operators for playback */ 375static struct snd_pcm_ops ct_pcm_playback_ops = { 376 .open = ct_pcm_playback_open, 377 .close = ct_pcm_playback_close, 378 .ioctl = snd_pcm_lib_ioctl, 379 .hw_params = ct_pcm_hw_params, 380 .hw_free = ct_pcm_hw_free, 381 .prepare = ct_pcm_playback_prepare, 382 .trigger = ct_pcm_playback_trigger, 383 .pointer = ct_pcm_playback_pointer, 384 .page = snd_pcm_sgbuf_ops_page, 385}; 386 387/* PCM operators for capture */ 388static struct snd_pcm_ops ct_pcm_capture_ops = { 389 .open = ct_pcm_capture_open, 390 .close = ct_pcm_capture_close, 391 .ioctl = snd_pcm_lib_ioctl, 392 .hw_params = ct_pcm_hw_params, 393 .hw_free = ct_pcm_hw_free, 394 .prepare = ct_pcm_capture_prepare, 395 .trigger = ct_pcm_capture_trigger, 396 .pointer = ct_pcm_capture_pointer, 397 .page = snd_pcm_sgbuf_ops_page, 398}; 399 400static const struct snd_pcm_chmap_elem surround_map[] = { 401 { .channels = 1, 402 .map = { SNDRV_CHMAP_MONO } }, 403 { .channels = 2, 404 .map = { SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } }, 405 { } 406}; 407 408static const struct snd_pcm_chmap_elem clfe_map[] = { 409 { .channels = 1, 410 .map = { SNDRV_CHMAP_MONO } }, 411 { .channels = 2, 412 .map = { SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE } }, 413 { } 414}; 415 416static const struct snd_pcm_chmap_elem side_map[] = { 417 { .channels = 1, 418 .map = { SNDRV_CHMAP_MONO } }, 419 { .channels = 2, 420 .map = { SNDRV_CHMAP_SL, SNDRV_CHMAP_SR } }, 421 { } 422}; 423 424/* Create ALSA pcm device */ 425int ct_alsa_pcm_create(struct ct_atc *atc, 426 enum CTALSADEVS device, 427 const char *device_name) 428{ 429 struct snd_pcm *pcm; 430 const struct snd_pcm_chmap_elem *map; 431 int chs; 432 int err; 433 int playback_count, capture_count; 434 435 playback_count = (IEC958 == device) ? 1 : 256; 436 capture_count = (FRONT == device) ? 1 : 0; 437 err = snd_pcm_new(atc->card, "ctxfi", device, 438 playback_count, capture_count, &pcm); 439 if (err < 0) { 440 dev_err(atc->card->dev, "snd_pcm_new failed!! Err=%d\n", 441 err); 442 return err; 443 } 444 445 pcm->private_data = atc; 446 pcm->info_flags = 0; 447 pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; 448 strlcpy(pcm->name, device_name, sizeof(pcm->name)); 449 450 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ct_pcm_playback_ops); 451 452 if (FRONT == device) 453 snd_pcm_set_ops(pcm, 454 SNDRV_PCM_STREAM_CAPTURE, &ct_pcm_capture_ops); 455 456 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, 457 snd_dma_pci_data(atc->pci), 128*1024, 128*1024); 458 459 chs = 2; 460 switch (device) { 461 case FRONT: 462 chs = 8; 463 map = snd_pcm_std_chmaps; 464 break; 465 case SURROUND: 466 map = surround_map; 467 break; 468 case CLFE: 469 map = clfe_map; 470 break; 471 case SIDE: 472 map = side_map; 473 break; 474 default: 475 map = snd_pcm_std_chmaps; 476 break; 477 } 478 err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, map, chs, 479 0, NULL); 480 if (err < 0) 481 return err; 482 483#ifdef CONFIG_PM_SLEEP 484 atc->pcms[device] = pcm; 485#endif 486 487 return 0; 488} 489