|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v2 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 |