[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v3 2/2] xen-sndfront: add capture support
From: Iurii Konovalenko <iurii.konovalenko@xxxxxxxxxxxxxxx> Now both play and capture is supported. Signed-off-by: Iurii Konovalenko <iurii.konovalenko@xxxxxxxxxxxxxxx> Signed-off-by: Oleksandr Dmytryshyn <oleksandr.dmytryshyn@xxxxxxxxxxxxxxx> --- sound/drivers/xen-sndfront.c | 193 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 164 insertions(+), 29 deletions(-) diff --git a/sound/drivers/xen-sndfront.c b/sound/drivers/xen-sndfront.c index d0367c2..054e535 100644 --- a/sound/drivers/xen-sndfront.c +++ b/sound/drivers/xen-sndfront.c @@ -98,7 +98,6 @@ MODULE_PARM_DESC(model, "Soundcard model."); #define MIXER_ADDR_LAST MIXER_ADDR_MASTER_OUT struct vsnd_card { - struct sndfront_info *fr_info; unsigned int stream_id; grant_ref_t grefs[SNDIF_MAX_PAGES_PER_REQUEST]; unsigned char *buf; @@ -123,7 +122,13 @@ struct sndfront_info { unsigned int evtchn, irq; struct vsnd_card *vcard; int bret_code; +}; + +struct vsnd_sndfront { + int count; + spinlock_t lock; /* protect 'count' member */ struct platform_device *card_dev; + struct sndfront_info *infos[2]; }; #define GRANT_INVALID_REF 0 @@ -160,7 +165,6 @@ struct snd_virtualcard { spinlock_t mixer_lock; /* protect mixer settings */ int mixer_volume[MIXER_ADDR_LAST+1][2]; int capture_source[MIXER_ADDR_LAST+1][2]; - struct sndfront_info *fr_info; struct stream_info streams[2]; }; @@ -206,6 +210,8 @@ static struct snd_pcm_hardware virtualcard_pcm_hardware = { .fifo_size = 0, }; +static struct vsnd_sndfront snd_fronts; + static inline struct stream_info *get_vcard_stream(struct snd_virtualcard *virtualcard, struct snd_pcm_substream *substream) @@ -216,6 +222,22 @@ struct stream_info *get_vcard_stream(struct snd_virtualcard *virtualcard, return &virtualcard->streams[1]; } +static inline +struct sndfront_info *get_sndfront_info(struct snd_pcm_substream *substream) +{ + struct sndfront_info *res = NULL; + int stream = substream->stream; + + spin_lock_irq(&snd_fronts.lock); + if ((stream == SNDRV_PCM_STREAM_PLAYBACK) && (snd_fronts.count > 0)) + res = snd_fronts.infos[0]; + else if ((stream == SNDRV_PCM_STREAM_CAPTURE) && (snd_fronts.count > 1)) + res = snd_fronts.infos[1]; + spin_unlock_irq(&snd_fronts.lock); + + return res; +} + static unsigned long vmalloc_to_mfn(void *address) { return pfn_to_mfn(vmalloc_to_pfn(address)); @@ -234,7 +256,8 @@ static inline void flush_requests(struct sndfront_info *info) static int sndif_queue_request_open(struct sndfront_info *info, snd_pcm_format_t format, unsigned int channels, - unsigned int rate) + unsigned int rate, + unsigned int stream) { struct sndif_request *req; @@ -248,6 +271,7 @@ static int sndif_queue_request_open(struct sndfront_info *info, req->u.open.snd_params.format = format; req->u.open.snd_params.channels = channels; req->u.open.snd_params.rate = rate; + req->u.open.stream = stream; info->ring.req_prod_pvt++; flush_requests(info); @@ -300,16 +324,48 @@ static int sndif_queue_request_write(struct sndfront_info *info, return 0; } +static int sndif_queue_request_read(struct sndfront_info *info, + unsigned int len) +{ + struct sndif_request *req; + grant_ref_t *gref; + int i; + + if (unlikely(info->connected != SNDIF_STATE_CONNECTED)) + return 1; + + req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt); + + req->operation = SNDIF_OP_READ; + req->u.rw.id = info->vcard->stream_id; + + req->u.rw.len = len; + + gref = info->vcard->grefs; + + for (i = 0; i < SNDIF_MAX_PAGES_PER_REQUEST; i++) + req->u.rw.gref[i] = gref[i]; + + info->ring.req_prod_pvt++; + + flush_requests(info); + return 0; +} + static int alsa_pcm_open(struct sndfront_info *info, snd_pcm_format_t format, unsigned int channels, - unsigned int rate) + unsigned int rate, + unsigned int stream) { unsigned long answer_tout; + if (!info) + return -EFAULT; + reinit_completion(&info->completion); - if (sndif_queue_request_open(info, format, channels, rate)) + if (sndif_queue_request_open(info, format, channels, rate, stream)) return -EIO; answer_tout = msecs_to_jiffies(VSND_WAIT_ANSWER_TOUT); @@ -324,6 +380,9 @@ static int alsa_pcm_close(struct sndfront_info *info) { unsigned long answer_tout; + if (!info) + return -EFAULT; + reinit_completion(&info->completion); if (sndif_queue_request_close(info)) @@ -343,6 +402,9 @@ static int alsa_pcm_write(struct sndfront_info *info, char __user *buf, unsigned char *shared_data; unsigned long answer_tout; + if (!info) + return -EFAULT; + shared_data = info->vcard->buf; if (len > PAGE_SIZE * SNDIF_MAX_PAGES_PER_REQUEST) @@ -364,6 +426,35 @@ static int alsa_pcm_write(struct sndfront_info *info, char __user *buf, return info->bret_code; } +static int alsa_pcm_read(struct sndfront_info *info, char __user *buf, + int len) +{ + unsigned char *shared_data; + unsigned long answer_tout; + + if (!info) + return -EFAULT; + + shared_data = info->vcard->buf; + + if (len > PAGE_SIZE * SNDIF_MAX_PAGES_PER_REQUEST) + return -EFAULT; + + reinit_completion(&info->completion); + + if (sndif_queue_request_read(info, len)) + return -EIO; + + answer_tout = msecs_to_jiffies(VSND_WAIT_ANSWER_TOUT); + if (wait_for_completion_interruptible_timeout(&info->completion, + answer_tout) <= 0) + return -ETIMEDOUT; + + if (copy_to_user(buf, shared_data, len)) + return -EFAULT; + + return info->bret_code; +} static int alsa_pcm_silence(struct sndfront_info *info, int len) { unsigned char *shared_data; @@ -458,7 +549,6 @@ static int sndif_add_virt_devices(struct sndfront_info *info, return -ENOMEM; vcard->stream_id = stream_id; - vcard->fr_info = info; info->vcard = vcard; @@ -520,6 +610,7 @@ static irqreturn_t sndif_interrupt(int irq, void *data) case SNDIF_OP_OPEN: case SNDIF_OP_CLOSE: case SNDIF_OP_WRITE: + case SNDIF_OP_READ: if (unlikely(bret->status != SNDIF_RSP_OKAY)) dev_dbg(&info->xbdev->dev, "snddev data request error: %x\n", @@ -677,16 +768,19 @@ static int virtualcard_pcm_prepare(struct snd_pcm_substream *substream) if ((runtime->rate != vcard_stream->rate) || (runtime->channels != vcard_stream->channels) || (runtime->format != vcard_stream->format)) { + struct sndfront_info *info = get_sndfront_info(substream); + if (vcard_stream->opened) { - err = alsa_pcm_close(virtualcard->fr_info); + err = alsa_pcm_close(info); if (err) return err; /* if closed successfully */ vcard_stream->opened = false; } - err = alsa_pcm_open(virtualcard->fr_info, runtime->format, - runtime->channels, runtime->rate); + + err = alsa_pcm_open(info, runtime->format, runtime->channels, + runtime->rate, substream->stream); if (err) return err; @@ -699,8 +793,8 @@ static int virtualcard_pcm_prepare(struct snd_pcm_substream *substream) return 0; } -static -snd_pcm_uframes_t virtualcard_pcm_pointer(struct snd_pcm_substream *substream) +static snd_pcm_uframes_t +virtualcard_pcm_playback_pointer(struct snd_pcm_substream *substream) { struct snd_virtualcard *virtualcard = snd_pcm_substream_chip(substream); snd_pcm_uframes_t buff_size = substream->runtime->buffer_size; @@ -721,6 +815,23 @@ snd_pcm_uframes_t virtualcard_pcm_pointer(struct snd_pcm_substream *substream) return vcard_stream->position; } +static snd_pcm_uframes_t +virtualcard_pcm_capture_pointer(struct snd_pcm_substream *substream) +{ + struct snd_virtualcard *virtualcard = snd_pcm_substream_chip(substream); + snd_pcm_uframes_t buff_size = substream->runtime->buffer_size, res; + struct stream_info *vcard_stream; + + vcard_stream = get_vcard_stream(virtualcard, substream); + +#ifdef MAX_CAPTURE_SIZE + res = (vcard_stream->position + MAX_CAPTURE_SIZE) % buff_size; +#else + res = (vcard_stream->position + buff_size / 2) % buff_size; +#endif + return res; +} + static int virtualcard_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { @@ -763,8 +874,9 @@ static int virtualcard_pcm_close(struct snd_pcm_substream *substream) { int err; struct snd_virtualcard *virtualcard = snd_pcm_substream_chip(substream); + struct sndfront_info *info = get_sndfront_info(substream); - err = alsa_pcm_close(virtualcard->fr_info); + err = alsa_pcm_close(info); if (err) return err; @@ -782,11 +894,11 @@ static int virtualcard_pcm_playback_copy(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; struct stream_info *vcard_stream = &virtualcard->streams[0]; snd_pcm_uframes_t stream_pos = vcard_stream->position; + struct sndfront_info *info = get_sndfront_info(substream); vcard_stream->position = (stream_pos + count) % runtime->buffer_size; vcard_stream->crossed = count / runtime->buffer_size; - return alsa_pcm_write(virtualcard->fr_info, src, - frames_to_bytes(runtime, count)); + return alsa_pcm_write(info, src, frames_to_bytes(runtime, count)); } static int virtualcard_pcm_playback_silence(struct snd_pcm_substream *substream, @@ -797,12 +909,12 @@ static int virtualcard_pcm_playback_silence(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; struct stream_info *vcard_stream = &virtualcard->streams[0]; snd_pcm_uframes_t stream_pos = vcard_stream->position; + struct sndfront_info *info = get_sndfront_info(substream); vcard_stream->position = (stream_pos + count) % runtime->buffer_size; vcard_stream->crossed = count / runtime->buffer_size; - return alsa_pcm_silence(virtualcard->fr_info, - frames_to_bytes(runtime, count)); + return alsa_pcm_silence(info, frames_to_bytes(runtime, count)); } static int virtualcard_pcm_capture_copy(struct snd_pcm_substream *substream, @@ -814,11 +926,12 @@ static int virtualcard_pcm_capture_copy(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; struct stream_info *vcard_stream = &virtualcard->streams[1]; snd_pcm_uframes_t stream_pos = vcard_stream->position; + struct sndfront_info *info = get_sndfront_info(substream); vcard_stream->position = (stream_pos + count) % runtime->buffer_size; vcard_stream->crossed = count / runtime->buffer_size; - return 0; + return alsa_pcm_read(info, dst, frames_to_bytes(runtime, count)); } static struct snd_pcm_ops virtualcard_pcm_playback_ops = { @@ -829,7 +942,7 @@ static struct snd_pcm_ops virtualcard_pcm_playback_ops = { .hw_free = virtualcard_pcm_hw_free, .prepare = virtualcard_pcm_prepare, .trigger = virtualcard_pcm_trigger, - .pointer = virtualcard_pcm_pointer, + .pointer = virtualcard_pcm_playback_pointer, .copy = virtualcard_pcm_playback_copy, .silence = virtualcard_pcm_playback_silence, }; @@ -842,7 +955,7 @@ static struct snd_pcm_ops virtualcard_pcm_capture_ops = { .hw_free = virtualcard_pcm_hw_free, .prepare = virtualcard_pcm_prepare, .trigger = virtualcard_pcm_trigger, - .pointer = virtualcard_pcm_pointer, + .pointer = virtualcard_pcm_capture_pointer, .copy = virtualcard_pcm_capture_copy, }; @@ -1160,8 +1273,6 @@ static int snd_virtualcard_probe(struct platform_device *devptr) return err; virtualcard = card->private_data; virtualcard->card = card; - virtualcard->fr_info = - (*((struct sndfront_info **)devptr->dev.platform_data)); m = virtualcard_models[0]; @@ -1271,7 +1382,7 @@ static struct platform_driver snd_virtualcard_driver = { static int sndfront_probe(struct xenbus_device *dev, const struct xenbus_device_id *id) { - int err; + int err, count; struct sndfront_info *info; info = kzalloc(sizeof(*info), GFP_KERNEL); @@ -1291,12 +1402,26 @@ static int sndfront_probe(struct xenbus_device *dev, if (err) goto err_free_info; - info->card_dev = platform_device_register_data(NULL, - SND_VIRTUALCARD_DRIVER, - -1, &info, sizeof(info)); - if (IS_ERR(info->card_dev)) { - err = -ENODEV; - goto err_free_info; + spin_lock_irq(&snd_fronts.lock); + snd_fronts.infos[snd_fronts.count] = info; + snd_fronts.count++; + count = snd_fronts.count; + spin_unlock_irq(&snd_fronts.lock); + + if (count == 1) { + struct platform_device *card_dev; + + card_dev = platform_device_register_data(NULL, + SND_VIRTUALCARD_DRIVER, + -1, NULL, 0); + snd_fronts.card_dev = card_dev; + if (IS_ERR(snd_fronts.card_dev)) { + spin_lock_irq(&snd_fronts.lock); + snd_fronts.count = 0; + spin_unlock_irq(&snd_fronts.lock); + err = -ENODEV; + goto err_free_info; + } } return 0; @@ -1418,11 +1543,19 @@ static void sndback_changed(struct xenbus_device *dev, static int sndfront_remove(struct xenbus_device *xbdev) { + int count; struct sndfront_info *info = dev_get_drvdata(&xbdev->dev); dev_dbg(&xbdev->dev, "%s removed", xbdev->nodename); - platform_device_unregister(info->card_dev); + spin_lock_irq(&snd_fronts.lock); + snd_fronts.count--; + count = snd_fronts.count; + snd_fronts.infos[count] = NULL; + spin_lock_irq(&snd_fronts.lock); + + if (!count) + platform_device_unregister(snd_fronts.card_dev); sndif_free(info, 0); @@ -1447,6 +1580,8 @@ static int __init xen_snd_front_init(void) { int ret = 0; + snd_fronts.count = 0; + spin_lock_init(&snd_fronts.lock); /*FIXME: xen_pv_domain() should be here, but ARM hardcoded to hvm*/ if (!xen_domain()) return -ENODEV; -- 1.9.1 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |