summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Chen <peter.chen@freescale.com>2011-12-19 11:08:31 +0800
committerPeter Chen <peter.chen@freescale.com>2011-12-26 14:36:28 +0800
commit6fa1892cdd8d2088af9dc67601c811cb6fcfa501 (patch)
tree2ac22b54d27ac54a7e5a7a24bebe5426c3ff293f
parent2ef1d55396f6ce0e6bf61f982b91bf7426fbca5d (diff)
ENGR00170819-1 usb-gadget: add usb audio support
- Only 44.1Khz audio are supported at i.MX6q, since only 44.1Khz local playback are supported at i.MX6q. - Since there is no feedback at current usb audio framework, it may have pop noise/no sound after play some minutes. - About how to test: please refer Documentation/arm/imx/udc.txt Signed-off-by: Peter Chen <peter.chen@freescale.com>
-rw-r--r--drivers/usb/gadget/f_audio.c36
-rw-r--r--drivers/usb/gadget/u_audio.c17
2 files changed, 45 insertions, 8 deletions
diff --git a/drivers/usb/gadget/f_audio.c b/drivers/usb/gadget/f_audio.c
index 3af0895469f3..2d285ec6e8bc 100644
--- a/drivers/usb/gadget/f_audio.c
+++ b/drivers/usb/gadget/f_audio.c
@@ -29,9 +29,16 @@ static int audio_buf_size = 48000;
module_param(audio_buf_size, int, S_IRUGO);
MODULE_PARM_DESC(audio_buf_size, "Audio buffer size");
+/* The first usb audio buf to alsa playback */
+static int first_audio_buf_size = 65500;
+module_param(first_audio_buf_size, int, S_IRUGO);
+MODULE_PARM_DESC(first_audio_buf_size, "First Audio buffer size");
+
static int generic_set_cmd(struct usb_audio_control *con, u8 cmd, int value);
static int generic_get_cmd(struct usb_audio_control *con, u8 cmd);
+/* Flag to use buffer with first_audio_buf_size to asla */
+static int first_copy_audio_buffer = 1;
/*
* DESCRIPTORS ... most are static, but strings and full
* configuration descriptors are built on demand.
@@ -329,13 +336,27 @@ static int f_audio_out_ep_complete(struct usb_ep *ep, struct usb_request *req)
if (!copy_buf)
return -EINVAL;
+ if (!first_copy_audio_buffer) {
/* Copy buffer is full, add it to the play_queue */
- if (audio_buf_size - copy_buf->actual < req->actual) {
- list_add_tail(&copy_buf->list, &audio->play_queue);
- schedule_work(&audio->playback_work);
- copy_buf = f_audio_buffer_alloc(audio_buf_size);
- if (IS_ERR(copy_buf))
- return -ENOMEM;
+ if (audio_buf_size - copy_buf->actual < req->actual) {
+ list_add_tail(&copy_buf->list, &audio->play_queue);
+ schedule_work(&audio->playback_work);
+ copy_buf = f_audio_buffer_alloc(audio_buf_size);
+
+ if (IS_ERR(copy_buf))
+ return -ENOMEM;
+ }
+ } else {
+ if (first_audio_buf_size - copy_buf->actual < req->actual) {
+ list_add_tail(&copy_buf->list, &audio->play_queue);
+ schedule_work(&audio->playback_work);
+ copy_buf = f_audio_buffer_alloc(audio_buf_size);
+
+ if (IS_ERR(copy_buf))
+ return -ENOMEM;
+
+ first_copy_audio_buffer = 0;
+ }
}
memcpy(copy_buf->buf + copy_buf->actual, req->buf, req->actual);
@@ -577,7 +598,7 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
if (alt == 1) {
usb_ep_enable(out_ep, audio->out_desc);
out_ep->driver_data = audio;
- audio->copy_buf = f_audio_buffer_alloc(audio_buf_size);
+ audio->copy_buf = f_audio_buffer_alloc(first_audio_buf_size);
if (IS_ERR(audio->copy_buf))
return -ENOMEM;
@@ -614,6 +635,7 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
&audio->play_queue);
schedule_work(&audio->playback_work);
}
+ first_copy_audio_buffer = 1;
}
}
diff --git a/drivers/usb/gadget/u_audio.c b/drivers/usb/gadget/u_audio.c
index 59ffe1ecf1c9..c72aeca692ed 100644
--- a/drivers/usb/gadget/u_audio.c
+++ b/drivers/usb/gadget/u_audio.c
@@ -39,6 +39,10 @@ static char *fn_cntl = FILE_CONTROL;
module_param(fn_cntl, charp, S_IRUGO);
MODULE_PARM_DESC(fn_cntl, "Control device file name");
+static int audio_sample_rate = 48000;
+module_param(audio_sample_rate, int, S_IRUGO);
+MODULE_PARM_DESC(audio_sample_rate, "Audio Sample Rate");
+
/*-------------------------------------------------------------------------*/
/**
@@ -122,13 +126,23 @@ static int playback_default_hw_params(struct gaudio_snd_dev *snd)
snd->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
snd->format = SNDRV_PCM_FORMAT_S16_LE;
snd->channels = 2;
- snd->rate = 48000;
+ if (audio_sample_rate == 44100)
+ snd->rate = 44100;
+ else if (audio_sample_rate == 48000)
+ snd->rate = 48000;
params = kzalloc(sizeof(*params), GFP_KERNEL);
if (!params)
return -ENOMEM;
_snd_pcm_hw_params_any(params);
+
+ if (audio_sample_rate == 44100) {
+ _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, \
+ 2*1024, 0);
+ _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, \
+ 16*1024, 0);
+ }
_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS,
snd->access, 0);
_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT,
@@ -193,6 +207,7 @@ try_again:
set_fs(KERNEL_DS);
result = snd_pcm_lib_write(snd->substream, buf, frames);
if (result != frames) {
+ msleep_interruptible(2);
ERROR(card, "Playback error: %d\n", (int)result);
set_fs(old_fs);
goto try_again;