~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/pci/ctxfi/ctpcm.c

Version: ~ [ linux-5.15-rc7 ] ~ [ linux-5.14.14 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.75 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.155 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.213 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.252 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.287 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.289 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 */
 24 static 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 
 49 static 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 */
 72 static 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 
 97 static 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 
107 static 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 */
119 static 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 
166 static 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 
179 static 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 
195 static 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 
207 static 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 
228 static int
229 ct_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 
253 static snd_pcm_uframes_t
254 ct_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 */
270 static 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 
312 static 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 
319 static 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 
336 static int
337 ct_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 
358 static snd_pcm_uframes_t
359 ct_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 */
375 static 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 */
388 static 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 
400 static 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 
408 static 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 
416 static 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 */
425 int 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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp