staging: bcm2835-audio: Simplify callback structure for write data
The device sends data to the audio devices by sending a message with the data through VC04_SERVICES/VCHIQ. This message contains a callback pointer that is always filled in with the same function. This is prone to corruption issues. Instead fill the callback fields with a fixed cookie value to perforam some validation on the message response and call the handler function directly instead of through the callback pointer. Signed-off-by: Michael Zoran <mzoran@crowfest.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
9c4f728693
commit
0cec463e39
@ -61,9 +61,8 @@ static void snd_bcm2835_playback_free(struct snd_pcm_runtime *runtime)
|
|||||||
runtime->private_data = NULL;
|
runtime->private_data = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static irqreturn_t bcm2835_playback_fifo_irq(int irq, void *dev_id)
|
void bcm2835_playback_fifo(struct bcm2835_alsa_stream *alsa_stream)
|
||||||
{
|
{
|
||||||
struct bcm2835_alsa_stream *alsa_stream = dev_id;
|
|
||||||
unsigned int consumed = 0;
|
unsigned int consumed = 0;
|
||||||
int new_period = 0;
|
int new_period = 0;
|
||||||
|
|
||||||
@ -103,8 +102,6 @@ static irqreturn_t bcm2835_playback_fifo_irq(int irq, void *dev_id)
|
|||||||
audio_warning(" unexpected NULL substream\n");
|
audio_warning(" unexpected NULL substream\n");
|
||||||
}
|
}
|
||||||
audio_info(" .. OUT\n");
|
audio_info(" .. OUT\n");
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* open callback */
|
/* open callback */
|
||||||
@ -164,10 +161,6 @@ static int snd_bcm2835_playback_open_generic(
|
|||||||
sema_init(&alsa_stream->control_sem, 0);
|
sema_init(&alsa_stream->control_sem, 0);
|
||||||
spin_lock_init(&alsa_stream->lock);
|
spin_lock_init(&alsa_stream->lock);
|
||||||
|
|
||||||
/* Enabled in start trigger, called on each "fifo irq" after that */
|
|
||||||
alsa_stream->enable_fifo_irq = 0;
|
|
||||||
alsa_stream->fifo_irq_handler = bcm2835_playback_fifo_irq;
|
|
||||||
|
|
||||||
err = bcm2835_audio_open(alsa_stream);
|
err = bcm2835_audio_open(alsa_stream);
|
||||||
if (err) {
|
if (err) {
|
||||||
kfree(alsa_stream);
|
kfree(alsa_stream);
|
||||||
|
@ -100,6 +100,11 @@ bcm2835_vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
|
|||||||
size);
|
size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const u32 BCM2835_AUDIO_WRITE_COOKIE1 = ('B' << 24 | 'C' << 16 ||
|
||||||
|
'M' << 8 | 'A');
|
||||||
|
static const u32 BCM2835_AUDIO_WRITE_COOKIE2 = ('D' << 24 | 'A' << 16 ||
|
||||||
|
'T' << 8 | 'A');
|
||||||
|
|
||||||
struct bcm2835_audio_work {
|
struct bcm2835_audio_work {
|
||||||
struct work_struct my_work;
|
struct work_struct my_work;
|
||||||
struct bcm2835_alsa_stream *alsa_stream;
|
struct bcm2835_alsa_stream *alsa_stream;
|
||||||
@ -248,21 +253,18 @@ static void audio_vchi_callback(void *param,
|
|||||||
complete(&instance->msg_avail_comp);
|
complete(&instance->msg_avail_comp);
|
||||||
} else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
|
} else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
|
||||||
struct bcm2835_alsa_stream *alsa_stream = instance->alsa_stream;
|
struct bcm2835_alsa_stream *alsa_stream = instance->alsa_stream;
|
||||||
#if defined(CONFIG_64BIT)
|
|
||||||
irq_handler_t callback =
|
|
||||||
(irq_handler_t) (((unsigned long) m.u.complete.callbackl) |
|
|
||||||
((unsigned long) m.u.complete.callbackh << 32));
|
|
||||||
#else
|
|
||||||
irq_handler_t callback = (irq_handler_t) m.u.complete.callback;
|
|
||||||
#endif
|
|
||||||
LOG_DBG(" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_COMPLETE, complete=%d\n",
|
LOG_DBG(" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_COMPLETE, complete=%d\n",
|
||||||
instance, m.u.complete.count);
|
instance, m.u.complete.count);
|
||||||
if (alsa_stream && callback) {
|
if (m.u.complete.cookie1 != BCM2835_AUDIO_WRITE_COOKIE1 ||
|
||||||
atomic_add(m.u.complete.count, &alsa_stream->retrieved);
|
m.u.complete.cookie2 != BCM2835_AUDIO_WRITE_COOKIE2)
|
||||||
callback(0, alsa_stream);
|
LOG_ERR(" .. response is corrupt\n");
|
||||||
|
else if (alsa_stream) {
|
||||||
|
atomic_add(m.u.complete.count,
|
||||||
|
&alsa_stream->retrieved);
|
||||||
|
bcm2835_playback_fifo(alsa_stream);
|
||||||
} else {
|
} else {
|
||||||
LOG_ERR(" .. unexpected alsa_stream=%p, callback=%p\n",
|
LOG_ERR(" .. unexpected alsa_stream=%p\n",
|
||||||
alsa_stream, callback);
|
alsa_stream);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOG_ERR(" .. unexpected m.type=%d\n", m.type);
|
LOG_ERR(" .. unexpected m.type=%d\n", m.type);
|
||||||
@ -815,13 +817,8 @@ int bcm2835_audio_write_worker(struct bcm2835_alsa_stream *alsa_stream,
|
|||||||
m.u.write.count = count;
|
m.u.write.count = count;
|
||||||
// old version uses bulk, new version uses control
|
// old version uses bulk, new version uses control
|
||||||
m.u.write.max_packet = instance->peer_version < 2 || force_bulk ? 0 : 4000;
|
m.u.write.max_packet = instance->peer_version < 2 || force_bulk ? 0 : 4000;
|
||||||
#if defined(CONFIG_64BIT)
|
m.u.write.cookie1 = BCM2835_AUDIO_WRITE_COOKIE1;
|
||||||
m.u.write.callbackl = (u32) (((unsigned long) alsa_stream->fifo_irq_handler)&0xFFFFFFFF);
|
m.u.write.cookie2 = BCM2835_AUDIO_WRITE_COOKIE2;
|
||||||
m.u.write.callbackh = (u32) ((((unsigned long) alsa_stream->fifo_irq_handler) >> 32)&0xFFFFFFFF);
|
|
||||||
#else
|
|
||||||
m.u.write.callback = alsa_stream->fifo_irq_handler;
|
|
||||||
m.u.write.cookie = alsa_stream;
|
|
||||||
#endif
|
|
||||||
m.u.write.silence = src == NULL;
|
m.u.write.silence = src == NULL;
|
||||||
|
|
||||||
/* Send the message to the videocore */
|
/* Send the message to the videocore */
|
||||||
|
@ -137,9 +137,6 @@ struct bcm2835_alsa_stream {
|
|||||||
unsigned int buffer_size;
|
unsigned int buffer_size;
|
||||||
unsigned int period_size;
|
unsigned int period_size;
|
||||||
|
|
||||||
unsigned int enable_fifo_irq;
|
|
||||||
irq_handler_t fifo_irq_handler;
|
|
||||||
|
|
||||||
atomic_t retrieved;
|
atomic_t retrieved;
|
||||||
struct bcm2835_audio_instance *instance;
|
struct bcm2835_audio_instance *instance;
|
||||||
struct workqueue_struct *my_wq;
|
struct workqueue_struct *my_wq;
|
||||||
@ -162,6 +159,7 @@ int bcm2835_audio_set_ctls(struct bcm2835_chip *chip);
|
|||||||
int bcm2835_audio_write(struct bcm2835_alsa_stream *alsa_stream,
|
int bcm2835_audio_write(struct bcm2835_alsa_stream *alsa_stream,
|
||||||
unsigned int count,
|
unsigned int count,
|
||||||
void *src);
|
void *src);
|
||||||
|
void bcm2835_playback_fifo(struct bcm2835_alsa_stream *alsa_stream);
|
||||||
unsigned int bcm2835_audio_retrieve_buffers(struct bcm2835_alsa_stream *alsa_stream);
|
unsigned int bcm2835_audio_retrieve_buffers(struct bcm2835_alsa_stream *alsa_stream);
|
||||||
void bcm2835_audio_flush_buffers(struct bcm2835_alsa_stream *alsa_stream);
|
void bcm2835_audio_flush_buffers(struct bcm2835_alsa_stream *alsa_stream);
|
||||||
void bcm2835_audio_flush_playback_buffers(struct bcm2835_alsa_stream *alsa_stream);
|
void bcm2835_audio_flush_playback_buffers(struct bcm2835_alsa_stream *alsa_stream);
|
||||||
|
@ -74,13 +74,8 @@ struct vc_audio_stop {
|
|||||||
/* configure the write audio samples */
|
/* configure the write audio samples */
|
||||||
struct vc_audio_write {
|
struct vc_audio_write {
|
||||||
u32 count; // in bytes
|
u32 count; // in bytes
|
||||||
#if defined(CONFIG_64BIT)
|
u32 cookie1;
|
||||||
u32 callbackl;
|
u32 cookie2;
|
||||||
u32 callbackh;
|
|
||||||
#else
|
|
||||||
void *callback;
|
|
||||||
void *cookie;
|
|
||||||
#endif
|
|
||||||
s16 silence;
|
s16 silence;
|
||||||
s16 max_packet;
|
s16 max_packet;
|
||||||
};
|
};
|
||||||
@ -93,13 +88,8 @@ struct vc_audio_result {
|
|||||||
/* Generic result for a request (VC->HOST) */
|
/* Generic result for a request (VC->HOST) */
|
||||||
struct vc_audio_complete {
|
struct vc_audio_complete {
|
||||||
s32 count; // Success value
|
s32 count; // Success value
|
||||||
#if defined(CONFIG_64BIT)
|
u32 cookie1;
|
||||||
u32 callbackl;
|
u32 cookie2;
|
||||||
u32 callbackh;
|
|
||||||
#else
|
|
||||||
void *callback;
|
|
||||||
void *cookie;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Message header for all messages in HOST->VC direction */
|
/* Message header for all messages in HOST->VC direction */
|
||||||
|
Loading…
Reference in New Issue
Block a user