]> err.no Git - linux-2.6/blobdiff - sound/core/pcm_native.c
[LLC]: Fix double receive of SKB.
[linux-2.6] / sound / core / pcm_native.c
index 263c01a70fdd413eeebc7dba28f98d4edf14a8fc..0860c5a84502f6f67451cdea60a566b639fdbf9b 100644 (file)
@@ -55,6 +55,7 @@ struct snd_pcm_hw_params_old {
        unsigned char reserved[64];
 };
 
+#ifdef CONFIG_SND_SUPPORT_OLD_API
 #define SNDRV_PCM_IOCTL_HW_REFINE_OLD _IOWR('A', 0x10, struct snd_pcm_hw_params_old)
 #define SNDRV_PCM_IOCTL_HW_PARAMS_OLD _IOWR('A', 0x11, struct snd_pcm_hw_params_old)
 
@@ -62,6 +63,8 @@ static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream,
                                      struct snd_pcm_hw_params_old __user * _oparams);
 static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream,
                                      struct snd_pcm_hw_params_old __user * _oparams);
+#endif
+static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream);
 
 /*
  *
@@ -1073,6 +1076,9 @@ int snd_pcm_suspend(struct snd_pcm_substream *substream)
        int err;
        unsigned long flags;
 
+       if (! substream)
+               return 0;
+
        snd_pcm_stream_lock_irqsave(substream, flags);
        err = snd_pcm_action(&snd_pcm_action_suspend, substream, 0);
        snd_pcm_stream_unlock_irqrestore(substream, flags);
@@ -1091,6 +1097,9 @@ int snd_pcm_suspend_all(struct snd_pcm *pcm)
        struct snd_pcm_substream *substream;
        int stream, err = 0;
 
+       if (! pcm)
+               return 0;
+
        for (stream = 0; stream < 2; stream++) {
                for (substream = pcm->streams[stream].substream;
                     substream; substream = substream->next) {
@@ -1161,7 +1170,7 @@ static int snd_pcm_resume(struct snd_pcm_substream *substream)
        int res;
 
        snd_power_lock(card);
-       if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile)) >= 0)
+       if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0)
                res = snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0);
        snd_power_unlock(card);
        return res;
@@ -1189,7 +1198,7 @@ static int snd_pcm_xrun(struct snd_pcm_substream *substream)
 
        snd_power_lock(card);
        if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
-               result = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile);
+               result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
                if (result < 0)
                        goto _unlock;
        }
@@ -1304,13 +1313,13 @@ static struct action_ops snd_pcm_action_prepare = {
  *
  * Prepare the PCM substream to be triggerable.
  */
-int snd_pcm_prepare(struct snd_pcm_substream *substream)
+static int snd_pcm_prepare(struct snd_pcm_substream *substream)
 {
        int res;
        struct snd_card *card = substream->pcm->card;
 
        snd_power_lock(card);
-       if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile)) >= 0)
+       if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0)
                res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare, substream, 0);
        snd_power_unlock(card);
        return res;
@@ -1401,7 +1410,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream)
 
        snd_power_lock(card);
        if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
-               result = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile);
+               result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
                if (result < 0) {
                        snd_power_unlock(card);
                        return result;
@@ -1524,7 +1533,7 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream)
 
        snd_power_lock(card);
        if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
-               result = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile);
+               result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
                if (result < 0)
                        goto _unlock;
        }
@@ -1548,7 +1557,8 @@ static struct file *snd_pcm_file_fd(int fd)
 {
        struct file *file;
        struct inode *inode;
-       unsigned short minor;
+       unsigned int minor;
+
        file = fget(fd);
        if (!file)
                return NULL;
@@ -1559,8 +1569,8 @@ static struct file *snd_pcm_file_fd(int fd)
                return NULL;
        }
        minor = iminor(inode);
-       if (minor >= 256 || 
-           minor % SNDRV_MINOR_DEVICES < SNDRV_MINOR_PCM_PLAYBACK) {
+       if (!snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_PLAYBACK) &&
+           !snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_CAPTURE)) {
                fput(file);
                return NULL;
        }
@@ -1985,28 +1995,65 @@ static void snd_pcm_remove_file(struct snd_pcm_str *str,
        }
 }
 
-static int snd_pcm_release_file(struct snd_pcm_file * pcm_file)
+static void pcm_release_private(struct snd_pcm_substream *substream)
 {
-       struct snd_pcm_substream *substream;
-       struct snd_pcm_runtime *runtime;
-       struct snd_pcm_str * str;
+       struct snd_pcm_file *pcm_file = substream->file;
 
-       snd_assert(pcm_file != NULL, return -ENXIO);
-       substream = pcm_file->substream;
-       snd_assert(substream != NULL, return -ENXIO);
-       runtime = substream->runtime;
-       str = substream->pstr;
        snd_pcm_unlink(substream);
-       if (substream->ffile != NULL) {
+       snd_pcm_remove_file(substream->pstr, pcm_file);
+       kfree(pcm_file);
+}
+
+void snd_pcm_release_substream(struct snd_pcm_substream *substream)
+{
+       snd_pcm_drop(substream);
+       if (substream->hw_opened) {
                if (substream->ops->hw_free != NULL)
                        substream->ops->hw_free(substream);
                substream->ops->close(substream);
-               substream->ffile = NULL;
+               substream->hw_opened = 0;
        }
-       snd_pcm_remove_file(str, pcm_file);
-       snd_pcm_release_substream(substream);
-       kfree(pcm_file);
+       if (substream->pcm_release) {
+               substream->pcm_release(substream);
+               substream->pcm_release = NULL;
+       }
+       snd_pcm_detach_substream(substream);
+}
+
+int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
+                          struct file *file,
+                          struct snd_pcm_substream **rsubstream)
+{
+       struct snd_pcm_substream *substream;
+       int err;
+
+       err = snd_pcm_attach_substream(pcm, stream, file, &substream);
+       if (err < 0)
+               return err;
+       substream->no_mmap_ctrl = 0;
+       err = snd_pcm_hw_constraints_init(substream);
+       if (err < 0) {
+               snd_printd("snd_pcm_hw_constraints_init failed\n");
+               goto error;
+       }
+
+       if ((err = substream->ops->open(substream)) < 0)
+               goto error;
+
+       substream->hw_opened = 1;
+
+       err = snd_pcm_hw_constraints_complete(substream);
+       if (err < 0) {
+               snd_printd("snd_pcm_hw_constraints_complete failed\n");
+               goto error;
+       }
+
+       *rsubstream = substream;
        return 0;
+
+ error:
+       snd_pcm_release_substream(substream);
+       return err;
 }
 
 static int snd_pcm_open_file(struct file *file,
@@ -2014,69 +2061,58 @@ static int snd_pcm_open_file(struct file *file,
                             int stream,
                             struct snd_pcm_file **rpcm_file)
 {
-       int err = 0;
        struct snd_pcm_file *pcm_file;
        struct snd_pcm_substream *substream;
        struct snd_pcm_str *str;
+       int err;
 
        snd_assert(rpcm_file != NULL, return -EINVAL);
        *rpcm_file = NULL;
 
+       err = snd_pcm_open_substream(pcm, stream, file, &substream);
+       if (err < 0)
+               return err;
+
        pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL);
        if (pcm_file == NULL) {
+               snd_pcm_release_substream(substream);
                return -ENOMEM;
        }
-
-       if ((err = snd_pcm_open_substream(pcm, stream, &substream)) < 0) {
-               kfree(pcm_file);
-               return err;
-       }
-
        str = substream->pstr;
        substream->file = pcm_file;
-       substream->no_mmap_ctrl = 0;
-
+       substream->pcm_release = pcm_release_private;
        pcm_file->substream = substream;
-
        snd_pcm_add_file(str, pcm_file);
 
-       err = snd_pcm_hw_constraints_init(substream);
-       if (err < 0) {
-               snd_printd("snd_pcm_hw_constraints_init failed\n");
-               snd_pcm_release_file(pcm_file);
-               return err;
-       }
-
-       if ((err = substream->ops->open(substream)) < 0) {
-               snd_pcm_release_file(pcm_file);
-               return err;
-       }
-       substream->ffile = file;
-
-       err = snd_pcm_hw_constraints_complete(substream);
-       if (err < 0) {
-               snd_printd("snd_pcm_hw_constraints_complete failed\n");
-               snd_pcm_release_file(pcm_file);
-               return err;
-       }
-
        file->private_data = pcm_file;
        *rpcm_file = pcm_file;
        return 0;
 }
 
-static int snd_pcm_open(struct inode *inode, struct file *file)
+static int snd_pcm_playback_open(struct inode *inode, struct file *file)
+{
+       struct snd_pcm *pcm;
+
+       pcm = snd_lookup_minor_data(iminor(inode),
+                                   SNDRV_DEVICE_TYPE_PCM_PLAYBACK);
+       return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK);
+}
+
+static int snd_pcm_capture_open(struct inode *inode, struct file *file)
 {
-       int cardnum = SNDRV_MINOR_CARD(iminor(inode));
-       int device = SNDRV_MINOR_DEVICE(iminor(inode));
-       int err;
        struct snd_pcm *pcm;
+
+       pcm = snd_lookup_minor_data(iminor(inode),
+                                   SNDRV_DEVICE_TYPE_PCM_CAPTURE);
+       return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE);
+}
+
+static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream)
+{
+       int err;
        struct snd_pcm_file *pcm_file;
        wait_queue_t wait;
 
-       if (device < SNDRV_MINOR_PCM_PLAYBACK || device >= SNDRV_MINOR_DEVICES)
-               return -ENXIO;
-       pcm = snd_pcm_devices[(cardnum * SNDRV_PCM_DEVICES) + (device % SNDRV_MINOR_PCMS)];
        if (pcm == NULL) {
                err = -ENODEV;
                goto __error1;
@@ -2090,9 +2126,9 @@ static int snd_pcm_open(struct inode *inode, struct file *file)
        }
        init_waitqueue_entry(&wait, current);
        add_wait_queue(&pcm->open_wait, &wait);
-       down(&pcm->open_mutex);
+       mutex_lock(&pcm->open_mutex);
        while (1) {
-               err = snd_pcm_open_file(file, pcm, device >= SNDRV_MINOR_PCM_CAPTURE ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK, &pcm_file);
+               err = snd_pcm_open_file(file, pcm, stream, &pcm_file);
                if (err >= 0)
                        break;
                if (err == -EAGAIN) {
@@ -2103,16 +2139,16 @@ static int snd_pcm_open(struct inode *inode, struct file *file)
                } else
                        break;
                set_current_state(TASK_INTERRUPTIBLE);
-               up(&pcm->open_mutex);
+               mutex_unlock(&pcm->open_mutex);
                schedule();
-               down(&pcm->open_mutex);
+               mutex_lock(&pcm->open_mutex);
                if (signal_pending(current)) {
                        err = -ERESTARTSYS;
                        break;
                }
        }
        remove_wait_queue(&pcm->open_wait, &wait);
-       up(&pcm->open_mutex);
+       mutex_unlock(&pcm->open_mutex);
        if (err < 0)
                goto __error;
        return err;
@@ -2136,11 +2172,10 @@ static int snd_pcm_release(struct inode *inode, struct file *file)
        snd_assert(substream != NULL, return -ENXIO);
        snd_assert(!atomic_read(&substream->runtime->mmap_count), );
        pcm = substream->pcm;
-       snd_pcm_drop(substream);
        fasync_helper(-1, file, 0, &substream->runtime->fasync);
-       down(&pcm->open_mutex);
-       snd_pcm_release_file(pcm_file);
-       up(&pcm->open_mutex);
+       mutex_lock(&pcm->open_mutex);
+       snd_pcm_release_substream(substream);
+       mutex_unlock(&pcm->open_mutex);
        wake_up(&pcm->open_wait);
        module_put(pcm->card->module);
        snd_card_file_remove(pcm->card, file);
@@ -2458,11 +2493,6 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream,
        return 0;
 }
                
-static int snd_pcm_playback_ioctl1(struct snd_pcm_substream *substream,
-                                  unsigned int cmd, void __user *arg);
-static int snd_pcm_capture_ioctl1(struct snd_pcm_substream *substream,
-                                 unsigned int cmd, void __user *arg);
-
 static int snd_pcm_common_ioctl1(struct snd_pcm_substream *substream,
                                 unsigned int cmd, void __user *arg)
 {
@@ -2507,14 +2537,24 @@ static int snd_pcm_common_ioctl1(struct snd_pcm_substream *substream,
                return snd_pcm_delay(substream, arg);
        case SNDRV_PCM_IOCTL_SYNC_PTR:
                return snd_pcm_sync_ptr(substream, arg);
+#ifdef CONFIG_SND_SUPPORT_OLD_API
        case SNDRV_PCM_IOCTL_HW_REFINE_OLD:
                return snd_pcm_hw_refine_old_user(substream, arg);
        case SNDRV_PCM_IOCTL_HW_PARAMS_OLD:
                return snd_pcm_hw_params_old_user(substream, arg);
+#endif
        case SNDRV_PCM_IOCTL_DRAIN:
                return snd_pcm_drain(substream);
        case SNDRV_PCM_IOCTL_DROP:
                return snd_pcm_drop(substream);
+       case SNDRV_PCM_IOCTL_PAUSE:
+       {
+               int res;
+               snd_pcm_stream_lock_irq(substream);
+               res = snd_pcm_pause(substream, (int)(unsigned long)arg);
+               snd_pcm_stream_unlock_irq(substream);
+               return res;
+       }
        }
        snd_printd("unknown ioctl = 0x%x\n", cmd);
        return -ENOTTY;
@@ -2595,14 +2635,6 @@ static int snd_pcm_playback_ioctl1(struct snd_pcm_substream *substream,
                __put_user(result, _frames);
                return result < 0 ? result : 0;
        }
-       case SNDRV_PCM_IOCTL_PAUSE:
-       {
-               int res;
-               snd_pcm_stream_lock_irq(substream);
-               res = snd_pcm_pause(substream, (int)(unsigned long)arg);
-               snd_pcm_stream_unlock_irq(substream);
-               return res;
-       }
        }
        return snd_pcm_common_ioctl1(substream, cmd, arg);
 }
@@ -2712,41 +2744,28 @@ static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd,
        return snd_pcm_capture_ioctl1(pcm_file->substream, cmd, (void __user *)arg);
 }
 
-int snd_pcm_kernel_playback_ioctl(struct snd_pcm_substream *substream,
-                                 unsigned int cmd, void *arg)
-{
-       mm_segment_t fs;
-       int result;
-       
-       fs = snd_enter_user();
-       result = snd_pcm_playback_ioctl1(substream, cmd, (void __user *)arg);
-       snd_leave_user(fs);
-       return result;
-}
-
-int snd_pcm_kernel_capture_ioctl(struct snd_pcm_substream *substream,
-                                unsigned int cmd, void *arg)
+int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream,
+                        unsigned int cmd, void *arg)
 {
        mm_segment_t fs;
        int result;
        
        fs = snd_enter_user();
-       result = snd_pcm_capture_ioctl1(substream, cmd, (void __user *)arg);
-       snd_leave_user(fs);
-       return result;
-}
-
-int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream,
-                        unsigned int cmd, void *arg)
-{
        switch (substream->stream) {
        case SNDRV_PCM_STREAM_PLAYBACK:
-               return snd_pcm_kernel_playback_ioctl(substream, cmd, arg);
+               result = snd_pcm_playback_ioctl1(substream,
+                                                cmd, (void __user *)arg);
+               break;
        case SNDRV_PCM_STREAM_CAPTURE:
-               return snd_pcm_kernel_capture_ioctl(substream, cmd, arg);
+               result = snd_pcm_capture_ioctl1(substream,
+                                               cmd, (void __user *)arg);
+               break;
        default:
-               return -EINVAL;
+               result = -EINVAL;
+               break;
        }
+       snd_leave_user(fs);
+       return result;
 }
 
 static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count,
@@ -3250,6 +3269,7 @@ static int snd_pcm_fasync(int fd, struct file * file, int on)
  *  To be removed helpers to keep binary compatibility
  */
 
+#ifdef CONFIG_SND_SUPPORT_OLD_API
 #define __OLD_TO_NEW_MASK(x) ((x&7)|((x&0x07fffff8)<<5))
 #define __NEW_TO_OLD_MASK(x) ((x&7)|((x&0xffffff00)>>5))
 
@@ -3359,45 +3379,35 @@ out:
        kfree(oparams);
        return err;
 }
+#endif /* CONFIG_SND_SUPPORT_OLD_API */
 
 /*
  *  Register section
  */
 
-static struct file_operations snd_pcm_f_ops_playback = {
-       .owner =        THIS_MODULE,
-       .write =        snd_pcm_write,
-       .writev =       snd_pcm_writev,
-       .open =         snd_pcm_open,
-       .release =      snd_pcm_release,
-       .poll =         snd_pcm_playback_poll,
-       .unlocked_ioctl =       snd_pcm_playback_ioctl,
-       .compat_ioctl = snd_pcm_ioctl_compat,
-       .mmap =         snd_pcm_mmap,
-       .fasync =       snd_pcm_fasync,
-};
-
-static struct file_operations snd_pcm_f_ops_capture = {
-       .owner =        THIS_MODULE,
-       .read =         snd_pcm_read,
-       .readv =        snd_pcm_readv,
-       .open =         snd_pcm_open,
-       .release =      snd_pcm_release,
-       .poll =         snd_pcm_capture_poll,
-       .unlocked_ioctl =       snd_pcm_capture_ioctl,
-       .compat_ioctl = snd_pcm_ioctl_compat,
-       .mmap =         snd_pcm_mmap,
-       .fasync =       snd_pcm_fasync,
-};
-
-struct snd_minor snd_pcm_reg[2] =
-{
+struct file_operations snd_pcm_f_ops[2] = {
        {
-               .comment =      "digital audio playback",
-               .f_ops =        &snd_pcm_f_ops_playback,
+               .owner =                THIS_MODULE,
+               .write =                snd_pcm_write,
+               .writev =               snd_pcm_writev,
+               .open =                 snd_pcm_playback_open,
+               .release =              snd_pcm_release,
+               .poll =                 snd_pcm_playback_poll,
+               .unlocked_ioctl =       snd_pcm_playback_ioctl,
+               .compat_ioctl =         snd_pcm_ioctl_compat,
+               .mmap =                 snd_pcm_mmap,
+               .fasync =               snd_pcm_fasync,
        },
        {
-               .comment =      "digital audio capture",
-               .f_ops =        &snd_pcm_f_ops_capture,
+               .owner =                THIS_MODULE,
+               .read =                 snd_pcm_read,
+               .readv =                snd_pcm_readv,
+               .open =                 snd_pcm_capture_open,
+               .release =              snd_pcm_release,
+               .poll =                 snd_pcm_capture_poll,
+               .unlocked_ioctl =       snd_pcm_capture_ioctl,
+               .compat_ioctl =         snd_pcm_ioctl_compat,
+               .mmap =                 snd_pcm_mmap,
+               .fasync =               snd_pcm_fasync,
        }
 };