blob: fc4fb7a3ecd191043dac42467094bfb75e71284b [file] [log] [blame]
Bryan Wuc6994e62009-06-03 09:17:58 -04001/*
Anna Perel432367a2012-09-20 10:55:32 +03002 * u_audio.c -- ALSA audio utilities for Gadget stack
Bryan Wuc6994e62009-06-03 09:17:58 -04003 *
Anna Perel432367a2012-09-20 10:55:32 +03004 * Copyright (c) 2012, The Linux Foundation. All rights reserved.
Bryan Wuc6994e62009-06-03 09:17:58 -04005 * Copyright (C) 2008 Bryan Wu <cooloney@kernel.org>
6 * Copyright (C) 2008 Analog Devices, Inc
7 *
8 * Enter bugs at http://blackfin.uclinux.org/
9 *
10 * Licensed under the GPL-2 or later.
11 */
12
13#include <linux/kernel.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090014#include <linux/slab.h>
Bryan Wuc6994e62009-06-03 09:17:58 -040015#include <linux/device.h>
16#include <linux/delay.h>
17#include <linux/ctype.h>
18#include <linux/random.h>
19#include <linux/syscalls.h>
20
Jassi Brar18b5b3b2012-02-02 21:59:53 +053021#include "u_uac1.h"
Bryan Wuc6994e62009-06-03 09:17:58 -040022
Anna Perel432367a2012-09-20 10:55:32 +030023#ifdef pr_fmt
24#undef pr_fmt
25#endif
26#define pr_fmt(fmt) "%s: " fmt, __func__
27
Bryan Wuc6994e62009-06-03 09:17:58 -040028/*
29 * This component encapsulates the ALSA devices for USB audio gadget
30 */
31
Anna Perel432367a2012-09-20 10:55:32 +030032#define FILE_PCM_PLAYBACK "/dev/snd/pcmC0D5p"
33#define FILE_PCM_CAPTURE "/dev/snd/pcmC0D6c"
Bryan Wuc6994e62009-06-03 09:17:58 -040034#define FILE_CONTROL "/dev/snd/controlC0"
35
36static char *fn_play = FILE_PCM_PLAYBACK;
37module_param(fn_play, charp, S_IRUGO);
38MODULE_PARM_DESC(fn_play, "Playback PCM device file name");
39
40static char *fn_cap = FILE_PCM_CAPTURE;
41module_param(fn_cap, charp, S_IRUGO);
42MODULE_PARM_DESC(fn_cap, "Capture PCM device file name");
43
44static char *fn_cntl = FILE_CONTROL;
45module_param(fn_cntl, charp, S_IRUGO);
46MODULE_PARM_DESC(fn_cntl, "Control device file name");
47
Anna Perel432367a2012-09-20 10:55:32 +030048static struct gaudio *the_card;
49
50static bool audio_reinit;
51
Bryan Wuc6994e62009-06-03 09:17:58 -040052/*-------------------------------------------------------------------------*/
53
54/**
55 * Some ALSA internal helper functions
56 */
57static int snd_interval_refine_set(struct snd_interval *i, unsigned int val)
58{
59 struct snd_interval t;
60 t.empty = 0;
61 t.min = t.max = val;
62 t.openmin = t.openmax = 0;
63 t.integer = 1;
64 return snd_interval_refine(i, &t);
65}
66
67static int _snd_pcm_hw_param_set(struct snd_pcm_hw_params *params,
68 snd_pcm_hw_param_t var, unsigned int val,
69 int dir)
70{
71 int changed;
72 if (hw_is_mask(var)) {
73 struct snd_mask *m = hw_param_mask(params, var);
74 if (val == 0 && dir < 0) {
75 changed = -EINVAL;
76 snd_mask_none(m);
77 } else {
78 if (dir > 0)
79 val++;
80 else if (dir < 0)
81 val--;
82 changed = snd_mask_refine_set(
83 hw_param_mask(params, var), val);
84 }
85 } else if (hw_is_interval(var)) {
86 struct snd_interval *i = hw_param_interval(params, var);
87 if (val == 0 && dir < 0) {
88 changed = -EINVAL;
89 snd_interval_none(i);
90 } else if (dir == 0)
91 changed = snd_interval_refine_set(i, val);
92 else {
93 struct snd_interval t;
94 t.openmin = 1;
95 t.openmax = 1;
96 t.empty = 0;
97 t.integer = 0;
98 if (dir < 0) {
99 t.min = val - 1;
100 t.max = val;
101 } else {
102 t.min = val;
103 t.max = val+1;
104 }
105 changed = snd_interval_refine(i, &t);
106 }
Anna Perel432367a2012-09-20 10:55:32 +0300107 } else {
Bryan Wuc6994e62009-06-03 09:17:58 -0400108 return -EINVAL;
Anna Perel432367a2012-09-20 10:55:32 +0300109 }
Bryan Wuc6994e62009-06-03 09:17:58 -0400110 if (changed) {
111 params->cmask |= 1 << var;
112 params->rmask |= 1 << var;
113 }
114 return changed;
115}
116/*-------------------------------------------------------------------------*/
117
Anna Perel432367a2012-09-20 10:55:32 +0300118static inline
119struct snd_interval *param_to_interval(struct snd_pcm_hw_params *p, int n)
120{
121 return &(p->intervals[n - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]);
122}
123
124int pcm_buffer_size(struct snd_pcm_hw_params *params)
125{
126 struct snd_interval *i =
127 param_to_interval(params, SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
128 pr_debug("buffer_bytes = (%d,%d) omin=%d omax=%d int=%d empty=%d\n",
129 i->min, i->max, i->openmin, i->openmax, i->integer, i->empty);
130 return i->min;
131}
132
133int pcm_period_size(struct snd_pcm_hw_params *params)
134{
135 struct snd_interval *i =
136 param_to_interval(params, SNDRV_PCM_HW_PARAM_PERIOD_BYTES);
137 return i->min;
138}
139
Bryan Wuc6994e62009-06-03 09:17:58 -0400140/**
141 * Set default hardware params
142 */
Anna Perel432367a2012-09-20 10:55:32 +0300143static int playback_prepare_params(struct gaudio_snd_dev *snd)
Bryan Wuc6994e62009-06-03 09:17:58 -0400144{
145 struct snd_pcm_substream *substream = snd->substream;
146 struct snd_pcm_hw_params *params;
147 snd_pcm_sframes_t result;
148
149 /*
150 * SNDRV_PCM_ACCESS_RW_INTERLEAVED,
151 * SNDRV_PCM_FORMAT_S16_LE
152 * CHANNELS: 2
Anna Perel432367a2012-09-20 10:55:32 +0300153 * RATE: 8000
Bryan Wuc6994e62009-06-03 09:17:58 -0400154 */
155 snd->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
156 snd->format = SNDRV_PCM_FORMAT_S16_LE;
157 snd->channels = 2;
Anna Perel432367a2012-09-20 10:55:32 +0300158 snd->rate = 8000;
Bryan Wuc6994e62009-06-03 09:17:58 -0400159
160 params = kzalloc(sizeof(*params), GFP_KERNEL);
161 if (!params)
162 return -ENOMEM;
163
164 _snd_pcm_hw_params_any(params);
165 _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS,
166 snd->access, 0);
167 _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT,
168 snd->format, 0);
169 _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_CHANNELS,
170 snd->channels, 0);
171 _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE,
172 snd->rate, 0);
173
Anna Perel432367a2012-09-20 10:55:32 +0300174 result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
175 if (result < 0)
176 pr_err("SNDRV_PCM_IOCTL_DROP failed: %d\n", (int)result);
Bryan Wuc6994e62009-06-03 09:17:58 -0400177
Anna Perel432367a2012-09-20 10:55:32 +0300178 result = snd_pcm_kernel_ioctl(substream,
179 SNDRV_PCM_IOCTL_HW_PARAMS, params);
Bryan Wuc6994e62009-06-03 09:17:58 -0400180 if (result < 0) {
Anna Perel432367a2012-09-20 10:55:32 +0300181 pr_err("SNDRV_PCM_IOCTL_HW_PARAMS failed: %d\n", (int)result);
Bryan Wuc6994e62009-06-03 09:17:58 -0400182 kfree(params);
183 return result;
184 }
185
Anna Perel432367a2012-09-20 10:55:32 +0300186 result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL);
187 if (result < 0)
188 pr_err("Preparing playback failed: %d\n", (int)result);
189
190
Bryan Wuc6994e62009-06-03 09:17:58 -0400191 /* Store the hardware parameters */
192 snd->access = params_access(params);
193 snd->format = params_format(params);
194 snd->channels = params_channels(params);
195 snd->rate = params_rate(params);
196
197 kfree(params);
198
Anna Perel432367a2012-09-20 10:55:32 +0300199 pr_debug("playback params: access %x, format %x, channels %d, rate %d\n",
Bryan Wuc6994e62009-06-03 09:17:58 -0400200 snd->access, snd->format, snd->channels, snd->rate);
201
202 return 0;
203}
204
Anna Perel432367a2012-09-20 10:55:32 +0300205static int capture_prepare_params(struct gaudio_snd_dev *snd)
206{
207 struct snd_pcm_substream *substream = snd->substream;
208 struct snd_pcm_runtime *runtime = substream->runtime;
209 struct snd_pcm_hw_params *params;
210 struct snd_pcm_sw_params *swparams;
211 unsigned long period_size;
212 unsigned long buffer_size;
213 snd_pcm_sframes_t result = 0;
214
215 /*
216 * SNDRV_PCM_ACCESS_RW_INTERLEAVED,
217 * SNDRV_PCM_FORMAT_S16_LE
218 * CHANNELS: 1
219 * RATE: 8000
220 */
221 snd->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
222 snd->format = SNDRV_PCM_FORMAT_S16_LE;
223 snd->channels = 1;
224 snd->rate = 8000;
225
226 params = kzalloc(sizeof(*params), GFP_KERNEL);
227 if (!params) {
228 pr_err("Failed to allocate hw params");
229 return -ENOMEM;
230 }
231
232 _snd_pcm_hw_params_any(params);
233 _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS,
234 snd->access, 0);
235 _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT,
236 snd->format, 0);
237 _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_CHANNELS,
238 snd->channels, 0);
239 _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE,
240 snd->rate, 0);
241
242 result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
243 if (result < 0)
244 pr_err("SNDRV_PCM_IOCTL_DROP failed: %d\n", (int)result);
245
246 result = snd_pcm_kernel_ioctl(substream,
247 SNDRV_PCM_IOCTL_HW_PARAMS, params);
248 if (result < 0) {
249 pr_err("SNDRV_PCM_IOCTL_HW_PARAMS failed: %d\n", (int)result);
250 kfree(params);
251 return result;
252 }
253
254 result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE,
255 NULL);
256 if (result < 0)
257 pr_err("Preparing capture failed: %d\n", (int)result);
258
259 /* Store the hardware parameters */
260 snd->access = params_access(params);
261 snd->format = params_format(params);
262 snd->channels = params_channels(params);
263 snd->rate = params_rate(params);
264
265 runtime->frame_bits = snd_pcm_format_physical_width(runtime->format);
266
267 kfree(params);
268
269 swparams = kzalloc(sizeof(*swparams), GFP_KERNEL);
270 if (!swparams) {
271 pr_err("Failed to allocate sw params");
272 return -ENOMEM;
273 }
274
275 buffer_size = pcm_buffer_size(params);
276 period_size = pcm_period_size(params);
277 swparams->avail_min = period_size/2;
278 swparams->xfer_align = period_size/2;
279
280 swparams->tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
281 swparams->period_step = 1;
282 swparams->start_threshold = 1;
283 swparams->stop_threshold = INT_MAX;
284 swparams->silence_size = 0;
285 swparams->silence_threshold = 0;
286
287 result = snd_pcm_kernel_ioctl(substream,
288 SNDRV_PCM_IOCTL_SW_PARAMS, swparams);
289 if (result < 0)
290 pr_err("SNDRV_PCM_IOCTL_SW_PARAMS failed: %d\n", (int)result);
291
292 kfree(swparams);
293
294 pr_debug("capture params: access %x, format %x, channels %d, rate %d\n",
295 snd->access, snd->format, snd->channels, snd->rate);
296
297 return result;
298}
299
300/**
301 * Set default hardware params
302 */
303static int playback_default_hw_params(struct gaudio_snd_dev *snd)
304{
305 struct snd_pcm_hw_params *params;
306
307 /*
308 * SNDRV_PCM_ACCESS_RW_INTERLEAVED,
309 * SNDRV_PCM_FORMAT_S16_LE
310 * CHANNELS: 2
311 * RATE: 8000
312 */
313 snd->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
314 snd->format = SNDRV_PCM_FORMAT_S16_LE;
315 snd->channels = 2;
316 snd->rate = 8000;
317
318 params = kzalloc(sizeof(*params), GFP_KERNEL);
319 if (!params)
320 return -ENOMEM;
321
322 _snd_pcm_hw_params_any(params);
323 _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS,
324 snd->access, 0);
325 _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT,
326 snd->format, 0);
327 _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_CHANNELS,
328 snd->channels, 0);
329 _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE,
330 snd->rate, 0);
331
332 /* Store the hardware parameters */
333 snd->access = params_access(params);
334 snd->format = params_format(params);
335 snd->channels = params_channels(params);
336 snd->rate = params_rate(params);
337
338 kfree(params);
339
340 pr_debug("playback params: access %x, format %x, channels %d, rate %d\n",
341 snd->access, snd->format, snd->channels, snd->rate);
342
343 return 0;
344}
345
346static int capture_default_hw_params(struct gaudio_snd_dev *snd)
347{
348 struct snd_pcm_hw_params *params;
349
350 /*
351 * SNDRV_PCM_ACCESS_RW_INTERLEAVED,
352 * SNDRV_PCM_FORMAT_S16_LE
353 * CHANNELS: 1
354 * RATE: 8000
355 */
356 snd->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
357 snd->format = SNDRV_PCM_FORMAT_S16_LE;
358 snd->channels = 1;
359 snd->rate = 8000;
360
361 params = kzalloc(sizeof(*params), GFP_KERNEL);
362 if (!params)
363 return -ENOMEM;
364
365 _snd_pcm_hw_params_any(params);
366 _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS,
367 snd->access, 0);
368 _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT,
369 snd->format, 0);
370 _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_CHANNELS,
371 snd->channels, 0);
372 _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE,
373 snd->rate, 0);
374
375 /* Store the hardware parameters */
376 snd->access = params_access(params);
377 snd->format = params_format(params);
378 snd->channels = params_channels(params);
379 snd->rate = params_rate(params);
380
381 kfree(params);
382
383 pr_debug("capture params: access %x, format %x, channels %d, rate %d\n",
384 snd->access, snd->format, snd->channels, snd->rate);
385
386 return 0;
387}
388
389static int gaudio_open_streams(void)
390{
391 struct gaudio_snd_dev *snd;
392 int res = 0;
393
394 if (!the_card) {
395 pr_err("%s: Card is NULL", __func__);
396 return -ENODEV;
397 }
398
399 pr_debug("Initialize hw params");
400
401 /* Open PCM playback device and setup substream */
402 snd = &the_card->playback;
403 res = playback_prepare_params(snd);
404 if (res) {
405 pr_err("Setting playback params failed: err %d", res);
406 return res;
407 }
408
409 pr_debug("Initialized playback params");
410
411 /* Open PCM capture device and setup substream */
412 snd = &the_card->capture;
413 res = capture_prepare_params(snd);
414 if (res) {
415 pr_err("Setting capture params failed: err %d", res);
416 return res;
417 }
418
419 pr_info("Initialized capture params");
420
421 return 0;
422}
423
424void u_audio_clear(void)
425{
426 audio_reinit = false;
427}
428
Bryan Wuc6994e62009-06-03 09:17:58 -0400429/**
430 * Playback audio buffer data by ALSA PCM device
431 */
432static size_t u_audio_playback(struct gaudio *card, void *buf, size_t count)
433{
434 struct gaudio_snd_dev *snd = &card->playback;
435 struct snd_pcm_substream *substream = snd->substream;
436 struct snd_pcm_runtime *runtime = substream->runtime;
437 mm_segment_t old_fs;
438 ssize_t result;
439 snd_pcm_sframes_t frames;
Anna Perel432367a2012-09-20 10:55:32 +0300440 int err = 0;
441
442 if (!count) {
443 pr_err("Buffer is empty, no data to play");
444 return 0;
445 }
446
447 if (!audio_reinit) {
448 err = gaudio_open_streams();
449 if (err) {
450 pr_err("Failed to init audio streams");
451 return 0;
452 }
453 audio_reinit = 1;
454 }
Bryan Wuc6994e62009-06-03 09:17:58 -0400455
456try_again:
457 if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
Anna Perel432367a2012-09-20 10:55:32 +0300458 runtime->status->state == SNDRV_PCM_STATE_SUSPENDED ||
459 runtime->status->state == SNDRV_PCM_STATE_SETUP) {
Bryan Wuc6994e62009-06-03 09:17:58 -0400460 result = snd_pcm_kernel_ioctl(substream,
461 SNDRV_PCM_IOCTL_PREPARE, NULL);
462 if (result < 0) {
Anna Perel432367a2012-09-20 10:55:32 +0300463 pr_err("Preparing playback failed: %d\n",
464 (int)result);
465 return result;
466 }
467 }
468
469 if (!runtime->frame_bits) {
470 pr_err("SND failure - runtime->frame_bits == 0");
471 return 0;
472 }
473
474 frames = bytes_to_frames(runtime, count);
475 pr_debug("runtime->frame_bits = %d, count = %d, frames = %d",
476 runtime->frame_bits, (int)count, (int)frames);
477
478 old_fs = get_fs();
479 set_fs(KERNEL_DS);
480 result = snd_pcm_lib_write(snd->substream, buf, frames);
481 if (result != frames) {
482 pr_err("snd_pcm_lib_write failed with err %d\n", (int)result);
483 set_fs(old_fs);
484 goto try_again;
485 }
486 set_fs(old_fs);
487
488 pr_debug("Done. Sent %d frames", (int)frames);
489
490 return 0;
491}
492
493static size_t u_audio_capture(struct gaudio *card, void *buf, size_t count)
494{
495 ssize_t result;
496 mm_segment_t old_fs;
497 snd_pcm_sframes_t frames;
498 int err = 0;
499
500 struct gaudio_snd_dev *snd = &card->capture;
501 struct snd_pcm_substream *substream = snd->substream;
502 struct snd_pcm_runtime *runtime = substream->runtime;
503
504 if (!audio_reinit) {
505 err = gaudio_open_streams();
506 if (err) {
507 pr_err("Failed to init audio streams: err %d", err);
508 return 0;
509 }
510 audio_reinit = 1;
511 }
512
513try_again:
514 if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
515 runtime->status->state == SNDRV_PCM_STATE_SUSPENDED ||
516 runtime->status->state == SNDRV_PCM_STATE_SETUP) {
517 result = snd_pcm_kernel_ioctl(substream,
518 SNDRV_PCM_IOCTL_PREPARE, NULL);
519 if (result < 0) {
520 pr_err("Preparing capture failed: %d\n",
Bryan Wuc6994e62009-06-03 09:17:58 -0400521 (int)result);
522 return result;
523 }
524 }
525
526 frames = bytes_to_frames(runtime, count);
Anna Perel432367a2012-09-20 10:55:32 +0300527
Bryan Wuc6994e62009-06-03 09:17:58 -0400528 old_fs = get_fs();
529 set_fs(KERNEL_DS);
Anna Perel432367a2012-09-20 10:55:32 +0300530
531 pr_debug("frames = %d, count = %d", (int)frames, count);
532
533 result = snd_pcm_lib_read(substream, buf, frames);
Bryan Wuc6994e62009-06-03 09:17:58 -0400534 if (result != frames) {
Anna Perel432367a2012-09-20 10:55:32 +0300535 pr_err("Capture error: %d\n", (int)result);
Bryan Wuc6994e62009-06-03 09:17:58 -0400536 set_fs(old_fs);
537 goto try_again;
538 }
Anna Perel432367a2012-09-20 10:55:32 +0300539
Bryan Wuc6994e62009-06-03 09:17:58 -0400540 set_fs(old_fs);
541
542 return 0;
543}
544
545static int u_audio_get_playback_channels(struct gaudio *card)
546{
Anna Perel432367a2012-09-20 10:55:32 +0300547 pr_debug("Return %d", card->playback.channels);
Bryan Wuc6994e62009-06-03 09:17:58 -0400548 return card->playback.channels;
549}
550
551static int u_audio_get_playback_rate(struct gaudio *card)
552{
Anna Perel432367a2012-09-20 10:55:32 +0300553 pr_debug("Return %d", card->playback.rate);
Bryan Wuc6994e62009-06-03 09:17:58 -0400554 return card->playback.rate;
555}
556
Anna Perel432367a2012-09-20 10:55:32 +0300557static int u_audio_get_capture_channels(struct gaudio *card)
558{
559 pr_debug("Return %d", card->capture.channels);
560 return card->capture.channels;
561}
562
563static int u_audio_get_capture_rate(struct gaudio *card)
564{
565 pr_debug("Return %d", card->capture.rate);
566 return card->capture.rate;
567}
568
569
Bryan Wuc6994e62009-06-03 09:17:58 -0400570/**
571 * Open ALSA PCM and control device files
572 * Initial the PCM or control device
573 */
574static int gaudio_open_snd_dev(struct gaudio *card)
575{
576 struct snd_pcm_file *pcm_file;
577 struct gaudio_snd_dev *snd;
Anna Perel432367a2012-09-20 10:55:32 +0300578 int res = 0;
Bryan Wuc6994e62009-06-03 09:17:58 -0400579
Anna Perel432367a2012-09-20 10:55:32 +0300580 if (!card) {
581 pr_err("%s: Card is NULL", __func__);
Bryan Wuc6994e62009-06-03 09:17:58 -0400582 return -ENODEV;
Anna Perel432367a2012-09-20 10:55:32 +0300583 }
Bryan Wuc6994e62009-06-03 09:17:58 -0400584 /* Open control device */
585 snd = &card->control;
586 snd->filp = filp_open(fn_cntl, O_RDWR, 0);
587 if (IS_ERR(snd->filp)) {
588 int ret = PTR_ERR(snd->filp);
Anna Perel432367a2012-09-20 10:55:32 +0300589 pr_err("unable to open sound control device file: %s\n",
Bryan Wuc6994e62009-06-03 09:17:58 -0400590 fn_cntl);
591 snd->filp = NULL;
592 return ret;
593 }
594 snd->card = card;
595
596 /* Open PCM playback device and setup substream */
597 snd = &card->playback;
598 snd->filp = filp_open(fn_play, O_WRONLY, 0);
599 if (IS_ERR(snd->filp)) {
Anna Perel432367a2012-09-20 10:55:32 +0300600 pr_err("No such PCM playback device: %s\n", fn_play);
Bryan Wuc6994e62009-06-03 09:17:58 -0400601 snd->filp = NULL;
Anna Perel432367a2012-09-20 10:55:32 +0300602 return -EINVAL;
Bryan Wuc6994e62009-06-03 09:17:58 -0400603 }
Anna Perel432367a2012-09-20 10:55:32 +0300604 pr_debug("Initialized PCM playback device: %s\n", fn_play);
605
Bryan Wuc6994e62009-06-03 09:17:58 -0400606 pcm_file = snd->filp->private_data;
607 snd->substream = pcm_file->substream;
608 snd->card = card;
Anna Perel432367a2012-09-20 10:55:32 +0300609 res = playback_default_hw_params(snd);
610 if (res) {
611 pr_err("Setting playback HW params failed: err %d", res);
612 return res;
613 }
Bryan Wuc6994e62009-06-03 09:17:58 -0400614
615 /* Open PCM capture device and setup substream */
616 snd = &card->capture;
617 snd->filp = filp_open(fn_cap, O_RDONLY, 0);
618 if (IS_ERR(snd->filp)) {
Anna Perel432367a2012-09-20 10:55:32 +0300619 pr_err("No such PCM capture device: %s\n", fn_cap);
Robin Callendere792b1b2009-08-02 11:38:58 -0700620 snd->substream = NULL;
621 snd->card = NULL;
Richard Röjforsdf4fede2010-12-01 11:53:00 +0100622 snd->filp = NULL;
Anna Perel432367a2012-09-20 10:55:32 +0300623 return -EINVAL;
Bryan Wuc6994e62009-06-03 09:17:58 -0400624 }
Bryan Wuc6994e62009-06-03 09:17:58 -0400625
Anna Perel432367a2012-09-20 10:55:32 +0300626 pcm_file = snd->filp->private_data;
627 snd->substream = pcm_file->substream;
628 snd->card = card;
629 res = capture_default_hw_params(snd);
630
631 if (res)
632 pr_err("Setting capture HW params failed: err %d", res);
633
634 return res;
Bryan Wuc6994e62009-06-03 09:17:58 -0400635}
636
637/**
638 * Close ALSA PCM and control device files
639 */
640static int gaudio_close_snd_dev(struct gaudio *gau)
641{
642 struct gaudio_snd_dev *snd;
643
Anna Perel432367a2012-09-20 10:55:32 +0300644 pr_debug("Enter");
Bryan Wuc6994e62009-06-03 09:17:58 -0400645 /* Close control device */
646 snd = &gau->control;
Richard Röjforsdf4fede2010-12-01 11:53:00 +0100647 if (snd->filp)
Bryan Wuc6994e62009-06-03 09:17:58 -0400648 filp_close(snd->filp, current->files);
649
650 /* Close PCM playback device and setup substream */
651 snd = &gau->playback;
Richard Röjforsdf4fede2010-12-01 11:53:00 +0100652 if (snd->filp)
Bryan Wuc6994e62009-06-03 09:17:58 -0400653 filp_close(snd->filp, current->files);
654
655 /* Close PCM capture device and setup substream */
656 snd = &gau->capture;
Richard Röjforsdf4fede2010-12-01 11:53:00 +0100657 if (snd->filp)
Bryan Wuc6994e62009-06-03 09:17:58 -0400658 filp_close(snd->filp, current->files);
659
660 return 0;
661}
662
Anna Perel432367a2012-09-20 10:55:32 +0300663
Bryan Wuc6994e62009-06-03 09:17:58 -0400664/**
665 * gaudio_setup - setup ALSA interface and preparing for USB transfer
666 *
667 * This sets up PCM, mixer or MIDI ALSA devices fore USB gadget using.
668 *
669 * Returns negative errno, or zero on success
670 */
Anna Perel432367a2012-09-20 10:55:32 +0300671int gaudio_setup(struct gaudio *card)
Bryan Wuc6994e62009-06-03 09:17:58 -0400672{
673 int ret;
674
675 ret = gaudio_open_snd_dev(card);
676 if (ret)
Anna Perel432367a2012-09-20 10:55:32 +0300677 pr_err("Failed to open snd devices\n");
Richard Röjforsdf4fede2010-12-01 11:53:00 +0100678 else if (!the_card)
Cliff Caifeef1d92009-12-09 22:28:39 -0500679 the_card = card;
680
Bryan Wuc6994e62009-06-03 09:17:58 -0400681 return ret;
Bryan Wuc6994e62009-06-03 09:17:58 -0400682}
683
684/**
685 * gaudio_cleanup - remove ALSA device interface
686 *
687 * This is called to free all resources allocated by @gaudio_setup().
688 */
Cliff Caifeef1d92009-12-09 22:28:39 -0500689void gaudio_cleanup(void)
Bryan Wuc6994e62009-06-03 09:17:58 -0400690{
Cliff Caifeef1d92009-12-09 22:28:39 -0500691 if (the_card) {
692 gaudio_close_snd_dev(the_card);
693 the_card = NULL;
694 }
Bryan Wuc6994e62009-06-03 09:17:58 -0400695}
696