[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 3/3] 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>
---
 include/xen/interface/io/sndif.h |  93 +++++++++++++---
 sound/drivers/xen-sndfront.c     | 222 ++++++++++++++++++++++++++++++---------
 2 files changed, 252 insertions(+), 63 deletions(-)

diff --git a/include/xen/interface/io/sndif.h b/include/xen/interface/io/sndif.h
index 2fae4df..dafd90b 100644
--- a/include/xen/interface/io/sndif.h
+++ b/include/xen/interface/io/sndif.h
@@ -11,17 +11,70 @@
 #include <xen/interface/grant_table.h>
 
 /*
+ * PCM FORMATS.
+ */
+#define SNDIF_PCM_FORMAT_S8            (0)
+#define SNDIF_PCM_FORMAT_U8            (1)
+#define SNDIF_PCM_FORMAT_S16_LE                (2)
+#define SNDIF_PCM_FORMAT_S16_BE                (3)
+#define SNDIF_PCM_FORMAT_U16_LE                (4)
+#define SNDIF_PCM_FORMAT_U16_BE                (5)
+
+/* low three bytes */
+#define SNDIF_PCM_FORMAT_S24_LE                (6)
+
+/* low three bytes */
+#define SNDIF_PCM_FORMAT_S24_BE                (7)
+
+/* low three bytes */
+#define SNDIF_PCM_FORMAT_U24_LE                (8)
+
+/* low three bytes */
+#define SNDIF_PCM_FORMAT_U24_BE                (9)
+
+#define SNDIF_PCM_FORMAT_S32_LE                (10)
+#define SNDIF_PCM_FORMAT_S32_BE                (11)
+#define SNDIF_PCM_FORMAT_U32_LE                (12)
+#define SNDIF_PCM_FORMAT_U32_BE                (13)
+
+/* 4-byte float, IEEE-754 32-bit, range -1.0 to 1.0 */
+#define SNDIF_PCM_FORMAT_FLOAT_LE      (14)
+
+/* 4-byte float, IEEE-754 32-bit, range -1.0 to 1.0 */
+#define SNDIF_PCM_FORMAT_FLOAT_BE      (15)
+
+/* 8-byte float, IEEE-754 64-bit, range -1.0 to 1.0 */
+#define SNDIF_PCM_FORMAT_FLOAT64_LE    (16)
+
+/* 8-byte float, IEEE-754 64-bit, range -1.0 to 1.0 */
+#define SNDIF_PCM_FORMAT_FLOAT64_BE    (17)
+
+/* IEC-958 subframe, Little Endian */
+#define SNDIF_PCM_FORMAT_IEC958_SUBFRAME_LE (18)
+
+/* IEC-958 subframe, Big Endian */
+#define SNDIF_PCM_FORMAT_IEC958_SUBFRAME_BE (19)
+
+#define SNDIF_PCM_FORMAT_MU_LAW                (20)
+#define SNDIF_PCM_FORMAT_A_LAW         (21)
+#define SNDIF_PCM_FORMAT_IMA_ADPCM     (22)
+#define SNDIF_PCM_FORMAT_MPEG          (23)
+#define SNDIF_PCM_FORMAT_GSM           (24)
+#define SNDIF_PCM_FORMAT_SPECIAL       (31)
+
+/*
  * REQUEST CODES.
  */
 #define SNDIF_OP_OPEN                  0
 #define SNDIF_OP_CLOSE                 1
 #define SNDIF_OP_READ                  2
 #define SNDIF_OP_WRITE                 3
-#define SNDIF_OP_IOCTL                 4
+#define SNDIF_SET_VOLUME               4
+#define SNDIF_GET_VOLUME               5
 
 #define SNDIF_MAX_PAGES_PER_REQUEST    10
 
-#define SNDIF_DEV_ID_CNT               5
+#define SNDIF_DEV_ID_CNT               2
 
 /*
  * STATUS RETURN CODES.
@@ -32,39 +85,47 @@
 #define SNDIF_RSP_OKAY         0
 
 struct alsa_hwparams {
-       snd_pcm_format_t format;
-       unsigned int channels;
-       unsigned int rate;
+       uint32_t format;
+       uint32_t channels;
+       uint32_t rate;
 };
 
+struct sndif_request_common {
+       uint64_t     id;           /* private guest value, echoed in resp  */
+       struct alsa_hwparams _pad1;
+       uint32_t _pad2;
+       uint32_t _pad3;
+} __attribute__((__packed__));
+
 struct sndif_request_open {
-       struct alsa_hwparams hwparams;
-       unsigned int _pad1;
        uint64_t     id;           /* private guest value, echoed in resp  */
-       unsigned int _pad2;
+       struct alsa_hwparams hwparams;
+       uint32_t stream;
+       uint32_t _pad2;
 } __attribute__((__packed__));
 
 struct sndif_request_rw {
-       struct alsa_hwparams _pad1;
-       unsigned int _pad2;
        uint64_t     id;           /* private guest value, echoed in resp  */
-       unsigned int len;
+       struct alsa_hwparams _pad1;
+       uint32_t len;
+       uint32_t _pad2;
        grant_ref_t gref[SNDIF_MAX_PAGES_PER_REQUEST];
 } __attribute__((__packed__));
 
-struct sndif_request_common {
-       struct alsa_hwparams _pad1;
-       unsigned int _pad2;
+struct sndif_request_volume {
        uint64_t     id;           /* private guest value, echoed in resp  */
-       unsigned int _pad3;
+       struct alsa_hwparams _pad1;
+       uint32_t left;
+       uint32_t right;
 } __attribute__((__packed__));
 
 struct sndif_request {
        uint8_t         operation;    /* SNDIF_OP_??? */
        union {
+               struct sndif_request_common common;
                struct sndif_request_open open;
                struct sndif_request_rw rw;
-               struct sndif_request_common common;
+               struct sndif_request_volume vol;
        } u;
 } __attribute__((__packed__));
 
diff --git a/sound/drivers/xen-sndfront.c b/sound/drivers/xen-sndfront.c
index da048fc..4bb02ec 100644
--- a/sound/drivers/xen-sndfront.c
+++ b/sound/drivers/xen-sndfront.c
@@ -95,8 +95,7 @@ MODULE_PARM_DESC(model, "Soundcard model.");
 #define MIXER_ADDR_LAST                        MIXER_ADDR_MASTER_OUT
 
 struct vsnd_card {
-       struct sndfront_info *fr_info;
-       unsigned int dev_id;
+       unsigned int stream_id;
        grant_ref_t grefs[SNDIF_MAX_PAGES_PER_REQUEST];
        unsigned char *buf;
 };
@@ -120,7 +119,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
@@ -157,7 +162,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];
 };
 
@@ -203,15 +207,33 @@ 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) {
+                                    struct snd_pcm_substream *substream)
+{
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                return &virtualcard->streams[0];
        else
                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)
 {
@@ -231,7 +253,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;
 
@@ -241,10 +264,11 @@ static int sndif_queue_request_open(struct sndfront_info 
*info,
        req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt);
 
        req->operation = SNDIF_OP_OPEN;
-       req->u.open.id = info->vcard->dev_id;
+       req->u.open.id = info->vcard->stream_id;
        req->u.open.hwparams.format = format;
        req->u.open.hwparams.channels = channels;
        req->u.open.hwparams.rate = rate;
+       req->u.open.stream = stream;
        info->ring.req_prod_pvt++;
 
        flush_requests(info);
@@ -261,7 +285,7 @@ static int sndif_queue_request_close(struct sndfront_info 
*info)
        req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt);
 
        req->operation = SNDIF_OP_CLOSE;
-       req->u.open.id = info->vcard->dev_id;
+       req->u.open.id = info->vcard->stream_id;
 
        info->ring.req_prod_pvt++;
 
@@ -282,7 +306,35 @@ static int sndif_queue_request_write(struct sndfront_info 
*info,
        req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt);
 
        req->operation = SNDIF_OP_WRITE;
-       req->u.rw.id = info->vcard->dev_id;
+       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 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;
 
@@ -300,13 +352,17 @@ static int sndif_queue_request_write(struct sndfront_info 
*info,
 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);
@@ -321,6 +377,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))
@@ -340,6 +399,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)
@@ -361,6 +423,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;
@@ -443,7 +534,7 @@ static void sndif_cleanup_vcard(struct sndfront_info *info)
 }
 
 static int sndif_add_virt_devices(struct sndfront_info *info,
-                                 unsigned int dev_id)
+                                 unsigned int stream_id)
 {
        int ret = 0;
 
@@ -454,8 +545,7 @@ static int sndif_add_virt_devices(struct sndfront_info 
*info,
        if (!vcard)
                return -ENOMEM;
 
-       vcard->dev_id = dev_id;
-       vcard->fr_info = info;
+       vcard->stream_id = stream_id;
 
        info->vcard = vcard;
 
@@ -517,6 +607,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",
@@ -674,16 +765,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;
 
@@ -696,26 +790,36 @@ 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;
-       struct stream_info *vcard_stream;
 
-       vcard_stream = get_vcard_stream(virtualcard, substream);
-
-       if (vcard_stream->crossed) {
+       if (virtualcard->streams[0].crossed) {
                snd_pcm_uframes_t hw_base = substream->runtime->hw_ptr_base;
-
                hw_base += buff_size;
                if (hw_base >= substream->runtime->boundary)
                        hw_base = 0;
 
                substream->runtime->hw_ptr_base = hw_base;
-               vcard_stream->crossed = 0;
+               virtualcard->streams[0].crossed = 0;
        }
-       return vcard_stream->position;
+       return virtualcard->streams[0].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;
+
+#ifdef MAX_CAPTURE_SIZE
+       res = (virtualcard->streams[1].position + MAX_CAPTURE_SIZE) % buff_size;
+#else
+       res = (virtualcard->streams[1].position + buff_size / 2) % buff_size;
+#endif
+       return res;
 }
 
 static int virtualcard_pcm_hw_params(struct snd_pcm_substream *substream,
@@ -760,8 +864,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;
 
@@ -779,11 +884,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,
@@ -794,12 +899,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,
@@ -811,11 +916,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 = {
@@ -826,7 +932,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,
 };
@@ -839,7 +945,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,
 };
 
@@ -1157,8 +1263,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];
 
@@ -1268,7 +1372,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);
@@ -1288,12 +1392,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;
 
@@ -1349,7 +1467,7 @@ sndfront_closing(struct sndfront_info *info)
  */
 static void sndfront_connect(struct sndfront_info *info)
 {
-       unsigned int dev_id;
+       unsigned int stream_id;
        int err;
 
        switch (info->connected) {
@@ -1368,12 +1486,12 @@ static void sndfront_connect(struct sndfront_info *info)
 
        xenbus_switch_state(info->xbdev, XenbusStateConnected);
 
-       err = xenbus_gather(XBT_NIL, info->xbdev->otherend, "dev_id", "%u",
-                           &dev_id, NULL);
+       err = xenbus_gather(XBT_NIL, info->xbdev->otherend, "stream_id", "%u",
+                           &stream_id, NULL);
        if (err)
                return;
 
-       err = sndif_add_virt_devices(info, dev_id);
+       err = sndif_add_virt_devices(info, stream_id);
        if (err)
                return;
 
@@ -1415,11 +1533,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);
 
@@ -1444,6 +1570,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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.