Skip to content

Commit

Permalink
ALSA: bcm2835: defer bcm2835 PCM write using the workqueue
Browse files Browse the repository at this point in the history
Only PCM playback and stop are deferred using a workqueue on
the ALSA bcm2835 driver. The actual writing of PCM samples
is synchronous.

This works well for the read/write transfer method since
the snd_pcm_ops .copy function pointer runs on process context.

But the snd_pcm_ops .ack function pointer used to implement
direct read/write transfer using a memory-mapped I/O, runs
with interrupts disabled. Since the Kernel to VideoCore
interface driver has to be able to sleep, PCM write has to be
deferred to in preparation to add mmap support to the driver.

Signed-off-by: Javier Martinez Canillas <[email protected]>
  • Loading branch information
Javier Martinez Canillas committed Apr 25, 2013
1 parent fd22e4c commit 24f64ad
Showing 1 changed file with 35 additions and 2 deletions.
37 changes: 35 additions & 2 deletions sound/arm/bcm2835-vchiq.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@

#define BCM2835_AUDIO_STOP 0
#define BCM2835_AUDIO_START 1
#define BCM2835_AUDIO_WRITE 2

/* Logging macros (for remapping to other logging mechanisms, i.e., printf) */
#ifdef AUDIO_DEBUG_ENABLE
Expand Down Expand Up @@ -74,11 +75,15 @@ bool force_bulk = false;

static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream);
static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream);
static int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
uint32_t count, void *src);

typedef struct {
struct work_struct my_work;
bcm2835_alsa_stream_t *alsa_stream;
int cmd;
void *src;
uint32_t count;
} my_work_t;

static void my_wq_function(struct work_struct *work)
Expand All @@ -93,6 +98,10 @@ static void my_wq_function(struct work_struct *work)
case BCM2835_AUDIO_STOP:
ret = bcm2835_audio_stop_worker(w->alsa_stream);
break;
case BCM2835_AUDIO_WRITE:
ret = bcm2835_audio_write_worker(w->alsa_stream, w->count,
w->src);
break;
default:
LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->cmd);
break;
Expand Down Expand Up @@ -143,6 +152,30 @@ int bcm2835_audio_stop(bcm2835_alsa_stream_t * alsa_stream)
return ret;
}

int bcm2835_audio_write(bcm2835_alsa_stream_t *alsa_stream,
uint32_t count, void *src)
{
int ret = -1;
LOG_DBG(" .. IN\n");
if (alsa_stream->my_wq) {
my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
/*--- Queue some work (item 1) ---*/
if (work) {
INIT_WORK((struct work_struct *)work, my_wq_function);
work->alsa_stream = alsa_stream;
work->cmd = BCM2835_AUDIO_WRITE;
work->src = src;
work->count = count;
if (queue_work
(alsa_stream->my_wq, (struct work_struct *)work))
ret = 0;
} else
LOG_ERR(" .. Error: NULL work kmalloc\n");
}
LOG_DBG(" .. OUT %d\n", ret);
return ret;
}

void my_workqueue_init(bcm2835_alsa_stream_t * alsa_stream)
{
alsa_stream->my_wq = create_workqueue("my_queue");
Expand Down Expand Up @@ -734,8 +767,8 @@ int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream)
return ret;
}

int bcm2835_audio_write(bcm2835_alsa_stream_t * alsa_stream, uint32_t count,
void *src)
int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
uint32_t count, void *src)
{
VC_AUDIO_MSG_T m;
AUDIO_INSTANCE_T *instance = alsa_stream->instance;
Expand Down

0 comments on commit 24f64ad

Please sign in to comment.