ALSA: hda - Fix invalid amp value for STAC925x
[safe/jmp/linux-2.6] / sound / core / pcm.c
index 2743414..192a433 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Digital Audio (PCM) abstract layer
- *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
  *
  *
  *   This program is free software; you can redistribute it and/or modify
@@ -19,7 +19,6 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/time.h>
@@ -30,7 +29,7 @@
 #include <sound/control.h>
 #include <sound/info.h>
 
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Abramo Bagnara <abramo@alsa-project.org>");
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Abramo Bagnara <abramo@alsa-project.org>");
 MODULE_DESCRIPTION("Midlevel PCM code for ALSA.");
 MODULE_LICENSE("GPL");
 
@@ -43,7 +42,7 @@ static int snd_pcm_dev_free(struct snd_device *device);
 static int snd_pcm_dev_register(struct snd_device *device);
 static int snd_pcm_dev_disconnect(struct snd_device *device);
 
-static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device)
+static struct snd_pcm *snd_pcm_get(struct snd_card *card, int device)
 {
        struct snd_pcm *pcm;
 
@@ -54,6 +53,37 @@ static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device)
        return NULL;
 }
 
+static int snd_pcm_next(struct snd_card *card, int device)
+{
+       struct snd_pcm *pcm;
+
+       list_for_each_entry(pcm, &snd_pcm_devices, list) {
+               if (pcm->card == card && pcm->device > device)
+                       return pcm->device;
+               else if (pcm->card->number > card->number)
+                       return -1;
+       }
+       return -1;
+}
+
+static int snd_pcm_add(struct snd_pcm *newpcm)
+{
+       struct snd_pcm *pcm;
+
+       list_for_each_entry(pcm, &snd_pcm_devices, list) {
+               if (pcm->card == newpcm->card && pcm->device == newpcm->device)
+                       return -EBUSY;
+               if (pcm->card->number > newpcm->card->number ||
+                               (pcm->card == newpcm->card &&
+                               pcm->device > newpcm->device)) {
+                       list_add(&newpcm->list, pcm->list.prev);
+                       return 0;
+               }
+       }
+       list_add_tail(&newpcm->list, &snd_pcm_devices);
+       return 0;
+}
+
 static int snd_pcm_control_ioctl(struct snd_card *card,
                                 struct snd_ctl_file *control,
                                 unsigned int cmd, unsigned long arg)
@@ -66,14 +96,7 @@ static int snd_pcm_control_ioctl(struct snd_card *card,
                        if (get_user(device, (int __user *)arg))
                                return -EFAULT;
                        mutex_lock(&register_mutex);
-                       device = device < 0 ? 0 : device + 1;
-                       while (device < SNDRV_PCM_DEVICES) {
-                               if (snd_pcm_search(card, device))
-                                       break;
-                               device++;
-                       }
-                       if (device == SNDRV_PCM_DEVICES)
-                               device = -1;
+                       device = snd_pcm_next(card, device);
                        mutex_unlock(&register_mutex);
                        if (put_user(device, (int __user *)arg))
                                return -EFAULT;
@@ -99,7 +122,7 @@ static int snd_pcm_control_ioctl(struct snd_card *card,
                        if (get_user(subdevice, &info->subdevice))
                                return -EFAULT;
                        mutex_lock(&register_mutex);
-                       pcm = snd_pcm_search(card, device);
+                       pcm = snd_pcm_get(card, device);
                        if (pcm == NULL) {
                                err = -ENXIO;
                                goto _error;
@@ -228,12 +251,11 @@ static char *snd_pcm_subformat_names[] = {
 
 static char *snd_pcm_tstamp_mode_names[] = {
        TSTAMP(NONE),
-       TSTAMP(MMAP),
+       TSTAMP(ENABLE),
 };
 
 static const char *snd_pcm_stream_name(int stream)
 {
-       snd_assert(stream <= SNDRV_PCM_STREAM_LAST, return NULL);
        return snd_pcm_stream_names[stream];
 }
 
@@ -249,7 +271,6 @@ static const char *snd_pcm_subformat_name(snd_pcm_subformat_t subformat)
 
 static const char *snd_pcm_tstamp_mode_name(int mode)
 {
-       snd_assert(mode <= SNDRV_PCM_TSTAMP_LAST, return NULL);
        return snd_pcm_tstamp_mode_names[mode];
 }
 
@@ -359,7 +380,6 @@ static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry,
        snd_iprintf(buffer, "rate: %u (%u/%u)\n", runtime->rate, runtime->rate_num, runtime->rate_den); 
        snd_iprintf(buffer, "period_size: %lu\n", runtime->period_size);        
        snd_iprintf(buffer, "buffer_size: %lu\n", runtime->buffer_size);        
-       snd_iprintf(buffer, "tick_time: %u\n", runtime->tick_time);
 #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
        if (substream->oss.oss) {
                snd_iprintf(buffer, "OSS format: %s\n", snd_pcm_oss_format_name(runtime->oss.format));
@@ -387,9 +407,7 @@ static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry,
        }
        snd_iprintf(buffer, "tstamp_mode: %s\n", snd_pcm_tstamp_mode_name(runtime->tstamp_mode));
        snd_iprintf(buffer, "period_step: %u\n", runtime->period_step);
-       snd_iprintf(buffer, "sleep_min: %u\n", runtime->sleep_min);
        snd_iprintf(buffer, "avail_min: %lu\n", runtime->control->avail_min);
-       snd_iprintf(buffer, "xfer_align: %lu\n", runtime->xfer_align);
        snd_iprintf(buffer, "start_threshold: %lu\n", runtime->start_threshold);
        snd_iprintf(buffer, "stop_threshold: %lu\n", runtime->stop_threshold);
        snd_iprintf(buffer, "silence_threshold: %lu\n", runtime->silence_threshold);
@@ -686,9 +704,10 @@ int snd_pcm_new(struct snd_card *card, char *id, int device,
                .dev_disconnect = snd_pcm_dev_disconnect,
        };
 
-       snd_assert(rpcm != NULL, return -EINVAL);
-       *rpcm = NULL;
-       snd_assert(card != NULL, return -ENXIO);
+       if (snd_BUG_ON(!card))
+               return -ENXIO;
+       if (rpcm)
+               *rpcm = NULL;
        pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
        if (pcm == NULL) {
                snd_printk(KERN_ERR "Cannot allocate PCM\n");
@@ -712,7 +731,8 @@ int snd_pcm_new(struct snd_card *card, char *id, int device,
                snd_pcm_free(pcm);
                return err;
        }
-       *rpcm = pcm;
+       if (rpcm)
+               *rpcm = pcm;
        return 0;
 }
 
@@ -746,7 +766,8 @@ static int snd_pcm_free(struct snd_pcm *pcm)
 {
        struct snd_pcm_notify *notify;
 
-       snd_assert(pcm != NULL, return -ENXIO);
+       if (!pcm)
+               return 0;
        list_for_each_entry(notify, &snd_pcm_notify_list, list) {
                notify->n_unregister(pcm);
        }
@@ -765,12 +786,6 @@ static int snd_pcm_dev_free(struct snd_device *device)
        return snd_pcm_free(pcm);
 }
 
-static void snd_pcm_tick_timer_func(unsigned long data)
-{
-       struct snd_pcm_substream *substream = (struct snd_pcm_substream *) data;
-       snd_pcm_tick_elapsed(substream);
-}
-
 int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
                             struct file *file,
                             struct snd_pcm_substream **rsubstream)
@@ -783,15 +798,15 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
        int prefer_subdevice = -1;
        size_t size;
 
-       snd_assert(rsubstream != NULL, return -EINVAL);
+       if (snd_BUG_ON(!pcm || !rsubstream))
+               return -ENXIO;
        *rsubstream = NULL;
-       snd_assert(pcm != NULL, return -ENXIO);
        pstr = &pcm->streams[stream];
        if (pstr->substream == NULL || pstr->substream_count == 0)
                return -ENODEV;
 
        card = pcm->card;
-       down_read(&card->controls_rwsem);
+       read_lock(&card->ctl_files_rwlock);
        list_for_each_entry(kctl, &card->ctl_files, list) {
                if (kctl->pid == current->pid) {
                        prefer_subdevice = kctl->prefer_pcm_subdevice;
@@ -799,7 +814,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
                                break;
                }
        }
-       up_read(&card->controls_rwsem);
+       read_unlock(&card->ctl_files_rwlock);
 
        switch (stream) {
        case SNDRV_PCM_STREAM_PLAYBACK:
@@ -877,9 +892,6 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
        memset((void*)runtime->control, 0, size);
 
        init_waitqueue_head(&runtime->sleep);
-       init_timer(&runtime->tick_timer);
-       runtime->tick_timer.function = snd_pcm_tick_timer_func;
-       runtime->tick_timer.data = (unsigned long) substream;
 
        runtime->status->state = SNDRV_PCM_STATE_OPEN;
 
@@ -896,8 +908,9 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime;
 
+       if (PCM_RUNTIME_CHECK(substream))
+               return;
        runtime = substream->runtime;
-       snd_assert(runtime != NULL, return);
        if (runtime->private_free != NULL)
                runtime->private_free(runtime);
        snd_free_pages((void*)runtime->status,
@@ -942,13 +955,14 @@ static int snd_pcm_dev_register(struct snd_device *device)
        struct snd_pcm *pcm = device->device_data;
        struct device *dev;
 
-       snd_assert(pcm != NULL && device != NULL, return -ENXIO);
+       if (snd_BUG_ON(!pcm || !device))
+               return -ENXIO;
        mutex_lock(&register_mutex);
-       if (snd_pcm_search(pcm->card, pcm->device)) {
+       err = snd_pcm_add(pcm);
+       if (err) {
                mutex_unlock(&register_mutex);
-               return -EBUSY;
+               return err;
        }
-       list_add_tail(&pcm->list, &snd_pcm_devices);
        for (cidx = 0; cidx < 2; cidx++) {
                int devtype = -1;
                if (pcm->streams[cidx].substream == NULL)
@@ -1032,10 +1046,11 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
 {
        struct snd_pcm *pcm;
 
-       snd_assert(notify != NULL &&
-                  notify->n_register != NULL &&
-                  notify->n_unregister != NULL &&
-                  notify->n_disconnect, return -EINVAL);
+       if (snd_BUG_ON(!notify ||
+                      !notify->n_register ||
+                      !notify->n_unregister ||
+                      !notify->n_disconnect))
+               return -EINVAL;
        mutex_lock(&register_mutex);
        if (nfree) {
                list_del(&notify->list);