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