Skip to content

Commit 027bc6d

Browse files
committed
Merge pull request #286 from martinezjavier/rpi-3.6.y-dev
add mmap support and some cleanups to bcm2835 ALSA driver
1 parent c729c47 commit 027bc6d

File tree

4 files changed

+124
-70
lines changed

4 files changed

+124
-70
lines changed

sound/arm/bcm2835-pcm.c

Lines changed: 43 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919

2020
/* hardware definition */
2121
static struct snd_pcm_hardware snd_bcm2835_playback_hw = {
22-
.info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER),
22+
.info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
23+
SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
2324
.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
2425
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
2526
.rate_min = 8000,
@@ -251,6 +252,12 @@ static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
251252

252253
audio_info(" .. IN\n");
253254

255+
memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
256+
257+
alsa_stream->pcm_indirect.hw_buffer_size =
258+
alsa_stream->pcm_indirect.sw_buffer_size =
259+
snd_pcm_lib_buffer_bytes(substream);
260+
254261
alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
255262
alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
256263
alsa_stream->pos = 0;
@@ -263,6 +270,32 @@ static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
263270
return 0;
264271
}
265272

273+
static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream,
274+
struct snd_pcm_indirect *rec, size_t bytes)
275+
{
276+
struct snd_pcm_runtime *runtime = substream->runtime;
277+
bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
278+
void *src = (void *)(substream->runtime->dma_area + rec->sw_data);
279+
int err;
280+
281+
err = bcm2835_audio_write(alsa_stream, bytes, src);
282+
if (err)
283+
audio_error(" Failed to transfer to alsa device (%d)\n", err);
284+
285+
}
286+
287+
static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream)
288+
{
289+
struct snd_pcm_runtime *runtime = substream->runtime;
290+
bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
291+
struct snd_pcm_indirect *pcm_indirect = &alsa_stream->pcm_indirect;
292+
293+
pcm_indirect->hw_queue_size = runtime->hw.buffer_bytes_max;
294+
snd_pcm_indirect_playback_transfer(substream, pcm_indirect,
295+
snd_bcm2835_pcm_transfer);
296+
return 0;
297+
}
298+
266299
/* trigger callback */
267300
static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
268301
{
@@ -279,6 +312,11 @@ static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
279312
if (!alsa_stream->running) {
280313
err = bcm2835_audio_start(alsa_stream);
281314
if (err == 0) {
315+
alsa_stream->pcm_indirect.hw_io =
316+
alsa_stream->pcm_indirect.hw_data =
317+
bytes_to_frames(runtime,
318+
alsa_stream->pos);
319+
substream->ops->ack(substream);
282320
alsa_stream->running = 1;
283321
alsa_stream->draining = 1;
284322
} else {
@@ -327,30 +365,9 @@ snd_bcm2835_pcm_pointer(struct snd_pcm_substream *substream)
327365
alsa_stream->pos);
328366

329367
audio_info(" .. OUT\n");
330-
return bytes_to_frames(runtime, alsa_stream->pos);
331-
}
332-
333-
static int snd_bcm2835_pcm_copy(struct snd_pcm_substream *substream,
334-
int channel, snd_pcm_uframes_t pos, void *src,
335-
snd_pcm_uframes_t count)
336-
{
337-
int ret;
338-
struct snd_pcm_runtime *runtime = substream->runtime;
339-
bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
340-
341-
audio_info(" .. IN\n");
342-
audio_debug("copy.......... (%d) hwptr=%d appl=%d pos=%d\n",
343-
frames_to_bytes(runtime, count), frames_to_bytes(runtime,
344-
runtime->
345-
status->
346-
hw_ptr),
347-
frames_to_bytes(runtime, runtime->control->appl_ptr),
348-
alsa_stream->pos);
349-
ret =
350-
bcm2835_audio_write(alsa_stream, frames_to_bytes(runtime, count),
351-
src);
352-
audio_info(" .. OUT\n");
353-
return ret;
368+
return snd_pcm_indirect_playback_pointer(substream,
369+
&alsa_stream->pcm_indirect,
370+
alsa_stream->pos);
354371
}
355372

356373
static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream,
@@ -372,7 +389,7 @@ static struct snd_pcm_ops snd_bcm2835_playback_ops = {
372389
.prepare = snd_bcm2835_pcm_prepare,
373390
.trigger = snd_bcm2835_pcm_trigger,
374391
.pointer = snd_bcm2835_pcm_pointer,
375-
.copy = snd_bcm2835_pcm_copy,
392+
.ack = snd_bcm2835_pcm_ack,
376393
};
377394

378395
/* create a pcm device */

sound/arm/bcm2835-vchiq.c

Lines changed: 62 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <linux/delay.h>
2828
#include <linux/atomic.h>
2929
#include <linux/module.h>
30+
#include <linux/completion.h>
3031

3132
#include "bcm2835.h"
3233

@@ -37,6 +38,10 @@
3738

3839
/* ---- Private Constants and Types ------------------------------------------ */
3940

41+
#define BCM2835_AUDIO_STOP 0
42+
#define BCM2835_AUDIO_START 1
43+
#define BCM2835_AUDIO_WRITE 2
44+
4045
/* Logging macros (for remapping to other logging mechanisms, i.e., printf) */
4146
#ifdef AUDIO_DEBUG_ENABLE
4247
#define LOG_ERR( fmt, arg... ) pr_err( "%s:%d " fmt, __func__, __LINE__, ##arg)
@@ -53,7 +58,7 @@
5358
typedef struct opaque_AUDIO_INSTANCE_T {
5459
uint32_t num_connections;
5560
VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS];
56-
struct semaphore msg_avail_event;
61+
struct completion msg_avail_comp;
5762
struct mutex vchi_mutex;
5863
bcm2835_alsa_stream_t *alsa_stream;
5964
int32_t result;
@@ -70,27 +75,35 @@ bool force_bulk = false;
7075

7176
static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream);
7277
static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream);
78+
static int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
79+
uint32_t count, void *src);
7380

7481
typedef struct {
7582
struct work_struct my_work;
7683
bcm2835_alsa_stream_t *alsa_stream;
77-
int x;
84+
int cmd;
85+
void *src;
86+
uint32_t count;
7887
} my_work_t;
7988

8089
static void my_wq_function(struct work_struct *work)
8190
{
8291
my_work_t *w = (my_work_t *) work;
8392
int ret = -9;
84-
LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->x);
85-
switch (w->x) {
86-
case 1:
93+
LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->cmd);
94+
switch (w->cmd) {
95+
case BCM2835_AUDIO_START:
8796
ret = bcm2835_audio_start_worker(w->alsa_stream);
8897
break;
89-
case 2:
98+
case BCM2835_AUDIO_STOP:
9099
ret = bcm2835_audio_stop_worker(w->alsa_stream);
91100
break;
101+
case BCM2835_AUDIO_WRITE:
102+
ret = bcm2835_audio_write_worker(w->alsa_stream, w->count,
103+
w->src);
104+
break;
92105
default:
93-
LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->x);
106+
LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->cmd);
94107
break;
95108
}
96109
kfree((void *)work);
@@ -107,7 +120,7 @@ int bcm2835_audio_start(bcm2835_alsa_stream_t * alsa_stream)
107120
if (work) {
108121
INIT_WORK((struct work_struct *)work, my_wq_function);
109122
work->alsa_stream = alsa_stream;
110-
work->x = 1;
123+
work->cmd = BCM2835_AUDIO_START;
111124
if (queue_work
112125
(alsa_stream->my_wq, (struct work_struct *)work))
113126
ret = 0;
@@ -128,7 +141,31 @@ int bcm2835_audio_stop(bcm2835_alsa_stream_t * alsa_stream)
128141
if (work) {
129142
INIT_WORK((struct work_struct *)work, my_wq_function);
130143
work->alsa_stream = alsa_stream;
131-
work->x = 2;
144+
work->cmd = BCM2835_AUDIO_STOP;
145+
if (queue_work
146+
(alsa_stream->my_wq, (struct work_struct *)work))
147+
ret = 0;
148+
} else
149+
LOG_ERR(" .. Error: NULL work kmalloc\n");
150+
}
151+
LOG_DBG(" .. OUT %d\n", ret);
152+
return ret;
153+
}
154+
155+
int bcm2835_audio_write(bcm2835_alsa_stream_t *alsa_stream,
156+
uint32_t count, void *src)
157+
{
158+
int ret = -1;
159+
LOG_DBG(" .. IN\n");
160+
if (alsa_stream->my_wq) {
161+
my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
162+
/*--- Queue some work (item 1) ---*/
163+
if (work) {
164+
INIT_WORK((struct work_struct *)work, my_wq_function);
165+
work->alsa_stream = alsa_stream;
166+
work->cmd = BCM2835_AUDIO_WRITE;
167+
work->src = src;
168+
work->count = count;
132169
if (queue_work
133170
(alsa_stream->my_wq, (struct work_struct *)work))
134171
ret = 0;
@@ -178,7 +215,7 @@ static void audio_vchi_callback(void *param,
178215
(" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_RESULT, success=%d\n",
179216
instance, m.u.result.success);
180217
instance->result = m.u.result.success;
181-
up(&instance->msg_avail_event);
218+
complete(&instance->msg_avail_comp);
182219
} else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
183220
irq_handler_t callback = (irq_handler_t) m.u.complete.callback;
184221
LOG_DBG
@@ -435,8 +472,8 @@ static int bcm2835_audio_set_ctls_chan(bcm2835_alsa_stream_t * alsa_stream,
435472
m.u.control.dest = chip->dest;
436473
m.u.control.volume = chip->volume;
437474

438-
/* Create the message available event */
439-
sema_init(&instance->msg_avail_event, 0);
475+
/* Create the message available completion */
476+
init_completion(&instance->msg_avail_comp);
440477

441478
/* Send the message to the videocore */
442479
success = vchi_msg_queue(instance->vchi_handle[0],
@@ -452,11 +489,10 @@ static int bcm2835_audio_set_ctls_chan(bcm2835_alsa_stream_t * alsa_stream,
452489
}
453490

454491
/* We are expecting a reply from the videocore */
455-
if (down_interruptible(&instance->msg_avail_event)) {
492+
ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
493+
if (ret) {
456494
LOG_ERR("%s: failed on waiting for event (status=%d)\n",
457495
__func__, success);
458-
459-
ret = -1;
460496
goto unlock;
461497
}
462498

@@ -539,8 +575,8 @@ int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
539575
m.u.config.samplerate = samplerate;
540576
m.u.config.bps = bps;
541577

542-
/* Create the message available event */
543-
sema_init(&instance->msg_avail_event, 0);
578+
/* Create the message available completion */
579+
init_completion(&instance->msg_avail_comp);
544580

545581
/* Send the message to the videocore */
546582
success = vchi_msg_queue(instance->vchi_handle[0],
@@ -556,11 +592,10 @@ int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
556592
}
557593

558594
/* We are expecting a reply from the videocore */
559-
if (down_interruptible(&instance->msg_avail_event)) {
595+
ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
596+
if (ret) {
560597
LOG_ERR("%s: failed on waiting for event (status=%d)\n",
561598
__func__, success);
562-
563-
ret = -1;
564599
goto unlock;
565600
}
566601

@@ -688,8 +723,8 @@ int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream)
688723

689724
m.type = VC_AUDIO_MSG_TYPE_CLOSE;
690725

691-
/* Create the message available event */
692-
sema_init(&instance->msg_avail_event, 0);
726+
/* Create the message available completion */
727+
init_completion(&instance->msg_avail_comp);
693728

694729
/* Send the message to the videocore */
695730
success = vchi_msg_queue(instance->vchi_handle[0],
@@ -702,11 +737,11 @@ int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream)
702737
ret = -1;
703738
goto unlock;
704739
}
705-
if (down_interruptible(&instance->msg_avail_event)) {
740+
741+
ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
742+
if (ret) {
706743
LOG_ERR("%s: failed on waiting for event (status=%d)",
707744
__func__, success);
708-
709-
ret = -1;
710745
goto unlock;
711746
}
712747
if (instance->result != 0) {
@@ -732,8 +767,8 @@ int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream)
732767
return ret;
733768
}
734769

735-
int bcm2835_audio_write(bcm2835_alsa_stream_t * alsa_stream, uint32_t count,
736-
void *src)
770+
int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
771+
uint32_t count, void *src)
737772
{
738773
VC_AUDIO_MSG_T m;
739774
AUDIO_INSTANCE_T *instance = alsa_stream->instance;

0 commit comments

Comments
 (0)