aboutsummaryrefslogtreecommitdiff
path: root/sound/core
diff options
context:
space:
mode:
Diffstat (limited to 'sound/core')
-rw-r--r--sound/core/control.c160
-rw-r--r--sound/core/control_compat.c4
-rw-r--r--sound/core/device.c20
-rw-r--r--sound/core/hwdep.c12
-rw-r--r--sound/core/info.c108
-rw-r--r--sound/core/info_oss.c6
-rw-r--r--sound/core/init.c116
-rw-r--r--sound/core/oss/mixer_oss.c22
-rw-r--r--sound/core/oss/pcm_oss.c24
-rw-r--r--sound/core/pcm.c128
-rw-r--r--sound/core/pcm_compat.c2
-rw-r--r--sound/core/pcm_memory.c2
-rw-r--r--sound/core/pcm_native.c49
-rw-r--r--sound/core/rawmidi.c38
-rw-r--r--sound/core/rtctimer.c2
-rw-r--r--sound/core/seq/oss/seq_oss.c3
-rw-r--r--sound/core/seq/seq_device.c13
-rw-r--r--sound/core/seq/seq_info.c6
-rw-r--r--sound/core/sound.c59
-rw-r--r--sound/core/sound_oss.c3
-rw-r--r--sound/core/timer.c62
21 files changed, 446 insertions, 393 deletions
diff --git a/sound/core/control.c b/sound/core/control.c
index bb397eaa718..6973a9686b6 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -75,6 +75,8 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
init_waitqueue_head(&ctl->change_sleep);
spin_lock_init(&ctl->read_lock);
ctl->card = card;
+ ctl->prefer_pcm_subdevice = -1;
+ ctl->prefer_rawmidi_subdevice = -1;
ctl->pid = current->pid;
file->private_data = ctl;
write_lock_irqsave(&card->ctl_files_rwlock, flags);
@@ -236,11 +238,16 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
kctl.id.index = ncontrol->index;
kctl.count = ncontrol->count ? ncontrol->count : 1;
access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
- (ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|SNDRV_CTL_ELEM_ACCESS_INACTIVE|
- SNDRV_CTL_ELEM_ACCESS_DINDIRECT|SNDRV_CTL_ELEM_ACCESS_INDIRECT));
+ (ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|
+ SNDRV_CTL_ELEM_ACCESS_INACTIVE|
+ SNDRV_CTL_ELEM_ACCESS_DINDIRECT|
+ SNDRV_CTL_ELEM_ACCESS_INDIRECT|
+ SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE|
+ SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK));
kctl.info = ncontrol->info;
kctl.get = ncontrol->get;
kctl.put = ncontrol->put;
+ kctl.tlv.p = ncontrol->tlv.p;
kctl.private_value = ncontrol->private_value;
kctl.private_data = private_data;
return snd_ctl_new(&kctl, access);
@@ -882,6 +889,8 @@ struct user_element {
struct snd_ctl_elem_info info;
void *elem_data; /* element data */
unsigned long elem_data_size; /* size of element data in bytes */
+ void *tlv_data; /* TLV data */
+ unsigned long tlv_data_size; /* TLV data size */
void *priv_data; /* private data (like strings for enumerated type) */
unsigned long priv_data_size; /* size of private data in bytes */
};
@@ -916,9 +925,48 @@ static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol,
return change;
}
+static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol,
+ int op_flag,
+ unsigned int size,
+ unsigned int __user *tlv)
+{
+ struct user_element *ue = kcontrol->private_data;
+ int change = 0;
+ void *new_data;
+
+ if (op_flag > 0) {
+ if (size > 1024 * 128) /* sane value */
+ return -EINVAL;
+ new_data = kmalloc(size, GFP_KERNEL);
+ if (new_data == NULL)
+ return -ENOMEM;
+ if (copy_from_user(new_data, tlv, size)) {
+ kfree(new_data);
+ return -EFAULT;
+ }
+ change = ue->tlv_data_size != size;
+ if (!change)
+ change = memcmp(ue->tlv_data, new_data, size);
+ kfree(ue->tlv_data);
+ ue->tlv_data = new_data;
+ ue->tlv_data_size = size;
+ } else {
+ if (! ue->tlv_data_size || ! ue->tlv_data)
+ return -ENXIO;
+ if (size < ue->tlv_data_size)
+ return -ENOSPC;
+ if (copy_to_user(tlv, ue->tlv_data, ue->tlv_data_size))
+ return -EFAULT;
+ }
+ return change;
+}
+
static void snd_ctl_elem_user_free(struct snd_kcontrol *kcontrol)
{
- kfree(kcontrol->private_data);
+ struct user_element *ue = kcontrol->private_data;
+ if (ue->tlv_data)
+ kfree(ue->tlv_data);
+ kfree(ue);
}
static int snd_ctl_elem_add(struct snd_ctl_file *file,
@@ -937,7 +985,8 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
return -EINVAL;
access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
(info->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|
- SNDRV_CTL_ELEM_ACCESS_INACTIVE));
+ SNDRV_CTL_ELEM_ACCESS_INACTIVE|
+ SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE));
info->id.numid = 0;
memset(&kctl, 0, sizeof(kctl));
down_write(&card->controls_rwsem);
@@ -963,6 +1012,10 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
kctl.get = snd_ctl_elem_user_get;
if (access & SNDRV_CTL_ELEM_ACCESS_WRITE)
kctl.put = snd_ctl_elem_user_put;
+ if (access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) {
+ kctl.tlv.c = snd_ctl_elem_user_tlv;
+ access |= SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
+ }
switch (info->type) {
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
private_size = sizeof(char);
@@ -997,6 +1050,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
if (ue == NULL)
return -ENOMEM;
ue->info = *info;
+ ue->info.access = 0;
ue->elem_data = (char *)ue + sizeof(*ue);
ue->elem_data_size = private_size;
kctl.private_free = snd_ctl_elem_user_free;
@@ -1067,6 +1121,67 @@ static int snd_ctl_subscribe_events(struct snd_ctl_file *file, int __user *ptr)
return 0;
}
+static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file,
+ struct snd_ctl_tlv __user *_tlv,
+ int op_flag)
+{
+ struct snd_card *card = file->card;
+ struct snd_ctl_tlv tlv;
+ struct snd_kcontrol *kctl;
+ struct snd_kcontrol_volatile *vd;
+ unsigned int len;
+ int err = 0;
+
+ if (copy_from_user(&tlv, _tlv, sizeof(tlv)))
+ return -EFAULT;
+ if (tlv.length < sizeof(unsigned int) * 3)
+ return -EINVAL;
+ down_read(&card->controls_rwsem);
+ kctl = snd_ctl_find_numid(card, tlv.numid);
+ if (kctl == NULL) {
+ err = -ENOENT;
+ goto __kctl_end;
+ }
+ if (kctl->tlv.p == NULL) {
+ err = -ENXIO;
+ goto __kctl_end;
+ }
+ vd = &kctl->vd[tlv.numid - kctl->id.numid];
+ if ((op_flag == 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) == 0) ||
+ (op_flag > 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) == 0) ||
+ (op_flag < 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND) == 0)) {
+ err = -ENXIO;
+ goto __kctl_end;
+ }
+ if (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
+ if (file && vd->owner != NULL && vd->owner != file) {
+ err = -EPERM;
+ goto __kctl_end;
+ }
+ err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv);
+ if (err > 0) {
+ up_read(&card->controls_rwsem);
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &kctl->id);
+ return 0;
+ }
+ } else {
+ if (op_flag) {
+ err = -ENXIO;
+ goto __kctl_end;
+ }
+ len = kctl->tlv.p[1] + 2 * sizeof(unsigned int);
+ if (tlv.length < len) {
+ err = -ENOMEM;
+ goto __kctl_end;
+ }
+ if (copy_to_user(_tlv->tlv, kctl->tlv.p, len))
+ err = -EFAULT;
+ }
+ __kctl_end:
+ up_read(&card->controls_rwsem);
+ return err;
+}
+
static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct snd_ctl_file *ctl;
@@ -1086,11 +1201,11 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
case SNDRV_CTL_IOCTL_CARD_INFO:
return snd_ctl_card_info(card, ctl, cmd, argp);
case SNDRV_CTL_IOCTL_ELEM_LIST:
- return snd_ctl_elem_list(ctl->card, argp);
+ return snd_ctl_elem_list(card, argp);
case SNDRV_CTL_IOCTL_ELEM_INFO:
return snd_ctl_elem_info_user(ctl, argp);
case SNDRV_CTL_IOCTL_ELEM_READ:
- return snd_ctl_elem_read_user(ctl->card, argp);
+ return snd_ctl_elem_read_user(card, argp);
case SNDRV_CTL_IOCTL_ELEM_WRITE:
return snd_ctl_elem_write_user(ctl, argp);
case SNDRV_CTL_IOCTL_ELEM_LOCK:
@@ -1105,6 +1220,12 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
return snd_ctl_elem_remove(ctl, argp);
case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
return snd_ctl_subscribe_events(ctl, ip);
+ case SNDRV_CTL_IOCTL_TLV_READ:
+ return snd_ctl_tlv_ioctl(ctl, argp, 0);
+ case SNDRV_CTL_IOCTL_TLV_WRITE:
+ return snd_ctl_tlv_ioctl(ctl, argp, 1);
+ case SNDRV_CTL_IOCTL_TLV_COMMAND:
+ return snd_ctl_tlv_ioctl(ctl, argp, -1);
case SNDRV_CTL_IOCTL_POWER:
return -ENOPROTOOPT;
case SNDRV_CTL_IOCTL_POWER_STATE:
@@ -1338,6 +1459,11 @@ static int snd_ctl_dev_disconnect(struct snd_device *device)
struct snd_card *card = device->device_data;
struct list_head *flist;
struct snd_ctl_file *ctl;
+ int err, cardnum;
+
+ snd_assert(card != NULL, return -ENXIO);
+ cardnum = card->number;
+ snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO);
down_read(&card->controls_rwsem);
list_for_each(flist, &card->ctl_files) {
@@ -1346,6 +1472,10 @@ static int snd_ctl_dev_disconnect(struct snd_device *device)
kill_fasync(&ctl->fasync, SIGIO, POLL_ERR);
}
up_read(&card->controls_rwsem);
+
+ if ((err = snd_unregister_device(SNDRV_DEVICE_TYPE_CONTROL,
+ card, -1)) < 0)
+ return err;
return 0;
}
@@ -1367,23 +1497,6 @@ static int snd_ctl_dev_free(struct snd_device *device)
}
/*
- * de-registration of the control device
- */
-static int snd_ctl_dev_unregister(struct snd_device *device)
-{
- struct snd_card *card = device->device_data;
- int err, cardnum;
-
- snd_assert(card != NULL, return -ENXIO);
- cardnum = card->number;
- snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO);
- if ((err = snd_unregister_device(SNDRV_DEVICE_TYPE_CONTROL,
- card, -1)) < 0)
- return err;
- return snd_ctl_dev_free(device);
-}
-
-/*
* create control core:
* called from init.c
*/
@@ -1393,7 +1506,6 @@ int snd_ctl_create(struct snd_card *card)
.dev_free = snd_ctl_dev_free,
.dev_register = snd_ctl_dev_register,
.dev_disconnect = snd_ctl_dev_disconnect,
- .dev_unregister = snd_ctl_dev_unregister
};
snd_assert(card != NULL, return -ENXIO);
diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c
index 3c0161bb5ba..ab48962c48c 100644
--- a/sound/core/control_compat.c
+++ b/sound/core/control_compat.c
@@ -407,6 +407,10 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns
case SNDRV_CTL_IOCTL_POWER_STATE:
case SNDRV_CTL_IOCTL_ELEM_LOCK:
case SNDRV_CTL_IOCTL_ELEM_UNLOCK:
+ case SNDRV_CTL_IOCTL_ELEM_REMOVE:
+ case SNDRV_CTL_IOCTL_TLV_READ:
+ case SNDRV_CTL_IOCTL_TLV_WRITE:
+ case SNDRV_CTL_IOCTL_TLV_COMMAND:
return snd_ctl_ioctl(file, cmd, (unsigned long)argp);
case SNDRV_CTL_IOCTL_ELEM_LIST32:
return snd_ctl_elem_list_compat(ctl->card, argp);
diff --git a/sound/core/device.c b/sound/core/device.c
index 6ce4da4a108..ccb25816ac9 100644
--- a/sound/core/device.c
+++ b/sound/core/device.c
@@ -71,7 +71,7 @@ EXPORT_SYMBOL(snd_device_new);
* @device_data: the data pointer to release
*
* Removes the device from the list on the card and invokes the
- * callback, dev_unregister or dev_free, corresponding to the state.
+ * callbacks, dev_disconnect and dev_free, corresponding to the state.
* Then release the device.
*
* Returns zero if successful, or a negative error code on failure or if the
@@ -90,16 +90,14 @@ int snd_device_free(struct snd_card *card, void *device_data)
continue;
/* unlink */
list_del(&dev->list);
- if ((dev->state == SNDRV_DEV_REGISTERED ||
- dev->state == SNDRV_DEV_DISCONNECTED) &&
- dev->ops->dev_unregister) {
- if (dev->ops->dev_unregister(dev))
- snd_printk(KERN_ERR "device unregister failure\n");
- } else {
- if (dev->ops->dev_free) {
- if (dev->ops->dev_free(dev))
- snd_printk(KERN_ERR "device free failure\n");
- }
+ if (dev->state == SNDRV_DEV_REGISTERED &&
+ dev->ops->dev_disconnect)
+ if (dev->ops->dev_disconnect(dev))
+ snd_printk(KERN_ERR
+ "device disconnect failure\n");
+ if (dev->ops->dev_free) {
+ if (dev->ops->dev_free(dev))
+ snd_printk(KERN_ERR "device free failure\n");
}
kfree(dev);
return 0;
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
index 8bd0dcc93eb..9aa9d94891f 100644
--- a/sound/core/hwdep.c
+++ b/sound/core/hwdep.c
@@ -42,7 +42,7 @@ static DEFINE_MUTEX(register_mutex);
static int snd_hwdep_free(struct snd_hwdep *hwdep);
static int snd_hwdep_dev_free(struct snd_device *device);
static int snd_hwdep_dev_register(struct snd_device *device);
-static int snd_hwdep_dev_unregister(struct snd_device *device);
+static int snd_hwdep_dev_disconnect(struct snd_device *device);
static struct snd_hwdep *snd_hwdep_search(struct snd_card *card, int device)
@@ -353,7 +353,7 @@ int snd_hwdep_new(struct snd_card *card, char *id, int device,
static struct snd_device_ops ops = {
.dev_free = snd_hwdep_dev_free,
.dev_register = snd_hwdep_dev_register,
- .dev_unregister = snd_hwdep_dev_unregister
+ .dev_disconnect = snd_hwdep_dev_disconnect,
};
snd_assert(rhwdep != NULL, return -EINVAL);
@@ -439,7 +439,7 @@ static int snd_hwdep_dev_register(struct snd_device *device)
return 0;
}
-static int snd_hwdep_dev_unregister(struct snd_device *device)
+static int snd_hwdep_dev_disconnect(struct snd_device *device)
{
struct snd_hwdep *hwdep = device->device_data;
@@ -454,9 +454,9 @@ static int snd_hwdep_dev_unregister(struct snd_device *device)
snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device);
#endif
snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device);
- list_del(&hwdep->list);
+ list_del_init(&hwdep->list);
mutex_unlock(&register_mutex);
- return snd_hwdep_free(hwdep);
+ return 0;
}
#ifdef CONFIG_PROC_FS
@@ -497,7 +497,7 @@ static void __init snd_hwdep_proc_init(void)
static void __exit snd_hwdep_proc_done(void)
{
- snd_info_unregister(snd_hwdep_proc_entry);
+ snd_info_free_entry(snd_hwdep_proc_entry);
}
#else /* !CONFIG_PROC_FS */
#define snd_hwdep_proc_init()
diff --git a/sound/core/info.c b/sound/core/info.c
index 340332c6d97..e43662b33f1 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -78,6 +78,7 @@ struct snd_info_private_data {
static int snd_info_version_init(void);
static int snd_info_version_done(void);
+static void snd_info_disconnect(struct snd_info_entry *entry);
/* resize the proc r/w buffer */
@@ -174,15 +175,15 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
switch (entry->content) {
case SNDRV_INFO_CONTENT_TEXT:
switch (orig) {
- case 0: /* SEEK_SET */
+ case SEEK_SET:
file->f_pos = offset;
ret = file->f_pos;
goto out;
- case 1: /* SEEK_CUR */
+ case SEEK_CUR:
file->f_pos += offset;
ret = file->f_pos;
goto out;
- case 2: /* SEEK_END */
+ case SEEK_END:
default:
ret = -EINVAL;
goto out;
@@ -304,7 +305,7 @@ static int snd_info_entry_open(struct inode *inode, struct file *file)
mutex_lock(&info_mutex);
p = PDE(inode);
entry = p == NULL ? NULL : (struct snd_info_entry *)p->data;
- if (entry == NULL || entry->disconnected) {
+ if (entry == NULL || ! entry->p) {
mutex_unlock(&info_mutex);
return -ENODEV;
}
@@ -586,10 +587,10 @@ int __exit snd_info_done(void)
snd_info_version_done();
if (snd_proc_root) {
#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
- snd_info_unregister(snd_seq_root);
+ snd_info_free_entry(snd_seq_root);
#endif
#ifdef CONFIG_SND_OSSEMUL
- snd_info_unregister(snd_oss_root);
+ snd_info_free_entry(snd_oss_root);
#endif
snd_remove_proc_entry(&proc_root, snd_proc_root);
}
@@ -648,17 +649,28 @@ int snd_info_card_register(struct snd_card *card)
* de-register the card proc file
* called from init.c
*/
-int snd_info_card_free(struct snd_card *card)
+void snd_info_card_disconnect(struct snd_card *card)
{
- snd_assert(card != NULL, return -ENXIO);
+ snd_assert(card != NULL, return);
+ mutex_lock(&info_mutex);
if (card->proc_root_link) {
snd_remove_proc_entry(snd_proc_root, card->proc_root_link);
card->proc_root_link = NULL;
}
- if (card->proc_root) {
- snd_info_unregister(card->proc_root);
- card->proc_root = NULL;
- }
+ if (card->proc_root)
+ snd_info_disconnect(card->proc_root);
+ mutex_unlock(&info_mutex);
+}
+
+/*
+ * release the card proc file resources
+ * called from init.c
+ */
+int snd_info_card_free(struct snd_card *card)
+{
+ snd_assert(card != NULL, return -ENXIO);
+ snd_info_free_entry(card->proc_root);
+ card->proc_root = NULL;
return 0;
}
@@ -767,6 +779,8 @@ static struct snd_info_entry *snd_info_create_entry(const char *name)
entry->mode = S_IFREG | S_IRUGO;
entry->content = SNDRV_INFO_CONTENT_TEXT;
mutex_init(&entry->access);
+ INIT_LIST_HEAD(&entry->children);
+ INIT_LIST_HEAD(&entry->list);
return entry;
}
@@ -819,30 +833,35 @@ struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card,
EXPORT_SYMBOL(snd_info_create_card_entry);
-static int snd_info_dev_free_entry(struct snd_device *device)
+static void snd_info_disconnect(struct snd_info_entry *entry)
{
- struct snd_info_entry *entry = device->device_data;
- snd_info_free_entry(entry);
- return 0;
-}
+ struct list_head *p, *n;
+ struct proc_dir_entry *root;
-static int snd_info_dev_register_entry(struct snd_device *device)
-{
- struct snd_info_entry *entry = device->device_data;
- return snd_info_register(entry);
+ list_for_each_safe(p, n, &entry->children) {
+ snd_info_disconnect(list_entry(p, struct snd_info_entry, list));
+ }
+
+ if (! entry->p)
+ return;
+ list_del_init(&entry->list);
+ root = entry->parent == NULL ? snd_proc_root : entry->parent->p;
+ snd_assert(root, return);
+ snd_remove_proc_entry(root, entry->p);
+ entry->p = NULL;
}
-static int snd_info_dev_disconnect_entry(struct snd_device *device)
+static int snd_info_dev_free_entry(struct snd_device *device)
{
struct snd_info_entry *entry = device->device_data;
- entry->disconnected = 1;
+ snd_info_free_entry(entry);
return 0;
}
-static int snd_info_dev_unregister_entry(struct snd_device *device)
+static int snd_info_dev_register_entry(struct snd_device *device)
{
struct snd_info_entry *entry = device->device_data;
- return snd_info_unregister(entry);
+ return snd_info_register(entry);
}
/**
@@ -871,8 +890,7 @@ int snd_card_proc_new(struct snd_card *card, const char *name,
static struct snd_device_ops ops = {
.dev_free = snd_info_dev_free_entry,
.dev_register = snd_info_dev_register_entry,
- .dev_disconnect = snd_info_dev_disconnect_entry,
- .dev_unregister = snd_info_dev_unregister_entry
+ /* disconnect is done via snd_info_card_disconnect() */
};
struct snd_info_entry *entry;
int err;
@@ -901,6 +919,11 @@ void snd_info_free_entry(struct snd_info_entry * entry)
{
if (entry == NULL)
return;
+ if (entry->p) {
+ mutex_lock(&info_mutex);
+ snd_info_disconnect(entry);
+ mutex_unlock(&info_mutex);
+ }
kfree(entry->name);
if (entry->private_free)
entry->private_free(entry);
@@ -935,38 +958,14 @@ int snd_info_register(struct snd_info_entry * entry)
p->size = entry->size;
p->data = entry;
entry->p = p;
+ if (entry->parent)
+ list_add_tail(&entry->list, &entry->parent->children);
mutex_unlock(&info_mutex);
return 0;
}
EXPORT_SYMBOL(snd_info_register);
-/**
- * snd_info_unregister - de-register the info entry
- * @entry: the info entry
- *
- * De-registers the info entry and releases the instance.
- *
- * Returns zero if successful, or a negative error code on failure.
- */
-int snd_info_unregister(struct snd_info_entry * entry)
-{
- struct proc_dir_entry *root;
-
- if (! entry)
- return 0;
- snd_assert(entry->p != NULL, return -ENXIO);
- root = entry->parent == NULL ? snd_proc_root : entry->parent->p;
- snd_assert(root, return -ENXIO);
- mutex_lock(&info_mutex);
- snd_remove_proc_entry(root, entry->p);
- mutex_unlock(&info_mutex);
- snd_info_free_entry(entry);
- return 0;
-}
-
-EXPORT_SYMBOL(snd_info_unregister);
-
/*
*/
@@ -999,8 +998,7 @@ static int __init snd_info_version_init(void)
static int __exit snd_info_version_done(void)
{
- if (snd_info_version_entry)
- snd_info_unregister(snd_info_version_entry);
+ snd_info_free_entry(snd_info_version_entry);
return 0;
}
diff --git a/sound/core/info_oss.c b/sound/core/info_oss.c
index bb2c40d0ab6..3ebc34919c7 100644
--- a/sound/core/info_oss.c
+++ b/sound/core/info_oss.c
@@ -131,10 +131,8 @@ int snd_info_minor_register(void)
int snd_info_minor_unregister(void)
{
- if (snd_sndstat_proc_entry) {
- snd_info_unregister(snd_sndstat_proc_entry);
- snd_sndstat_proc_entry = NULL;
- }
+ snd_info_free_entry(snd_sndstat_proc_entry);
+ snd_sndstat_proc_entry = NULL;
return 0;
}
diff --git a/sound/core/init.c b/sound/core/init.c
index 4d9258884e4..d7607a25acd 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -81,8 +81,6 @@ static inline int init_info_for_card(struct snd_card *card)
#define init_info_for_card(card)
#endif
-static void snd_card_free_thread(void * __card);
-
/**
* snd_card_new - create and initialize a soundcard structure
* @idx: card index (address) [0 ... (SNDRV_CARDS-1)]
@@ -145,7 +143,6 @@ struct snd_card *snd_card_new(int idx, const char *xid,
INIT_LIST_HEAD(&card->ctl_files);
spin_lock_init(&card->files_lock);
init_waitqueue_head(&card->shutdown_sleep);
- INIT_WORK(&card->free_workq, snd_card_free_thread, card);
#ifdef CONFIG_PM
mutex_init(&card->power_lock);
init_waitqueue_head(&card->power_sleep);
@@ -310,6 +307,7 @@ int snd_card_disconnect(struct snd_card *card)
if (err < 0)
snd_printk(KERN_ERR "not all devices for card %i can be disconnected\n", card->number);
+ snd_info_card_disconnect(card);
return 0;
}
@@ -326,22 +324,10 @@ EXPORT_SYMBOL(snd_card_disconnect);
* Returns zero. Frees all associated devices and frees the control
* interface associated to given soundcard.
*/
-int snd_card_free(struct snd_card *card)
+static int snd_card_do_free(struct snd_card *card)
{
struct snd_shutdown_f_ops *s_f_ops;
- if (card == NULL)
- return -EINVAL;
- mutex_lock(&snd_card_mutex);
- snd_cards[card->number] = NULL;
- mutex_unlock(&snd_card_mutex);
-
-#ifdef CONFIG_PM
- wake_up(&card->power_sleep);
-#endif
- /* wait, until all devices are ready for the free operation */
- wait_event(card->shutdown_sleep, card->files == NULL);
-
#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
if (snd_mixer_oss_notify_callback)
snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE);
@@ -360,7 +346,7 @@ int snd_card_free(struct snd_card *card)
}
if (card->private_free)
card->private_free(card);
- snd_info_unregister(card->proc_id);
+ snd_info_free_entry(card->proc_id);
if (snd_info_card_free(card) < 0) {
snd_printk(KERN_WARNING "unable to free card info\n");
/* Not fatal error */
@@ -370,61 +356,59 @@ int snd_card_free(struct snd_card *card)
card->s_f_ops = s_f_ops->next;
kfree(s_f_ops);
}
+ kfree(card);
+ return 0;
+}
+
+static int snd_card_free_prepare(struct snd_card *card)
+{
+ if (card == NULL)
+ return -EINVAL;
+ (void) snd_card_disconnect(card);
mutex_lock(&snd_card_mutex);
+ snd_cards[card->number] = NULL;
snd_cards_lock &= ~(1 << card->number);
mutex_unlock(&snd_card_mutex);
- kfree(card);
+#ifdef CONFIG_PM
+ wake_up(&card->power_sleep);
+#endif
return 0;
}
-EXPORT_SYMBOL(snd_card_free);
-
-static void snd_card_free_thread(void * __card)
+int snd_card_free_when_closed(struct snd_card *card)
{
- struct snd_card *card = __card;
- struct module * module = card->module;
-
- if (!try_module_get(module)) {
- snd_printk(KERN_ERR "unable to lock toplevel module for card %i in free thread\n", card->number);
- module = NULL;
- }
+ int free_now = 0;
+ int ret = snd_card_free_prepare(card);
+ if (ret)
+ return ret;
- snd_card_free(card);
+ spin_lock(&card->files_lock);
+ if (card->files == NULL)
+ free_now = 1;
+ else
+ card->free_on_last_close = 1;
+ spin_unlock(&card->files_lock);
- module_put(module);
+ if (free_now)
+ snd_card_do_free(card);
+ return 0;
}
-/**
- * snd_card_free_in_thread - call snd_card_free() in thread
- * @card: soundcard structure
- *
- * This function schedules the call of snd_card_free() function in a
- * work queue. When all devices are released (non-busy), the work
- * is woken up and calls snd_card_free().
- *
- * When a card can be disconnected at any time by hotplug service,
- * this function should be used in disconnect (or detach) callback
- * instead of calling snd_card_free() directly.
- *
- * Returns - zero otherwise a negative error code if the start of thread failed.
- */
-int snd_card_free_in_thread(struct snd_card *card)
-{
- if (card->files == NULL) {
- snd_card_free(card);
- return 0;
- }
+EXPORT_SYMBOL(snd_card_free_when_closed);
- if (schedule_work(&card->free_workq))
- return 0;
+int snd_card_free(struct snd_card *card)
+{
+ int ret = snd_card_free_prepare(card);
+ if (ret)
+ return ret;
- snd_printk(KERN_ERR "schedule_work() failed in snd_card_free_in_thread for card %i\n", card->number);
- /* try to free the structure immediately */
- snd_card_free(card);
- return -EFAULT;
+ /* wait, until all devices are ready for the free operation */
+ wait_event(card->shutdown_sleep, card->files == NULL);
+ snd_card_do_free(card);
+ return 0;
}
-EXPORT_SYMBOL(snd_card_free_in_thread);
+EXPORT_SYMBOL(snd_card_free);
static void choose_default_id(struct snd_card *card)
{
@@ -625,9 +609,9 @@ int __init snd_card_info_init(void)
int __exit snd_card_info_done(void)
{
- snd_info_unregister(snd_card_info_entry);
+ snd_info_free_entry(snd_card_info_entry);
#ifdef MODULE
- snd_info_unregister(snd_card_module_info_entry);
+ snd_info_free_entry(snd_card_module_info_entry);
#endif
return 0;
}
@@ -708,15 +692,16 @@ EXPORT_SYMBOL(snd_card_file_add);
*
* This function removes the file formerly added to the card via
* snd_card_file_add() function.
- * If all files are removed and the release of the card is
- * scheduled, it will wake up the the thread to call snd_card_free()
- * (see snd_card_free_in_thread() function).
+ * If all files are removed and snd_card_free_when_closed() was
+ * called beforehand, it processes the pending release of
+ * resources.
*
* Returns zero or a negative error code.
*/
int snd_card_file_remove(struct snd_card *card, struct file *file)
{
struct snd_monitor_file *mfile, *pfile = NULL;
+ int last_close = 0;
spin_lock(&card->files_lock);
mfile = card->files;
@@ -731,9 +716,14 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)
pfile = mfile;
mfile = mfile->next;
}
- spin_unlock(&card->files_lock);
if (card->files == NULL)
+ last_close = 1;
+ spin_unlock(&card->files_lock);
+ if (last_close) {
wake_up(&card->shutdown_sleep);
+ if (card->free_on_last_close)
+ snd_card_do_free(card);
+ }
if (!mfile) {
snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file);
return -ENOENT;
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index 75a9505c744..f4c67042e3a 100644
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -1193,10 +1193,8 @@ static void snd_mixer_oss_proc_init(struct snd_mixer_oss *mixer)
static void snd_mixer_oss_proc_done(struct snd_mixer_oss *mixer)
{
- if (mixer->proc_entry) {
- snd_info_unregister(mixer->proc_entry);
- mixer->proc_entry = NULL;
- }
+ snd_info_free_entry(mixer->proc_entry);
+ mixer->proc_entry = NULL;
}
#else /* !CONFIG_PROC_FS */
#define snd_mixer_oss_proc_init(mix)
@@ -1312,21 +1310,19 @@ static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd)
card->mixer_oss = mixer;
snd_mixer_oss_build(mixer);
snd_mixer_oss_proc_init(mixer);
- } else if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT) {
- mixer = card->mixer_oss;
- if (mixer == NULL || !mixer->oss_dev_alloc)
- return 0;
- snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0);
- mixer->oss_dev_alloc = 0;
- } else { /* free */
+ } else {
mixer = card->mixer_oss;
if (mixer == NULL)
return 0;
+ if (mixer->oss_dev_alloc) {
#ifdef SNDRV_OSS_INFO_DEV_MIXERS
- snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number);
+ snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number);
#endif
- if (mixer->oss_dev_alloc)
snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0);
+ mixer->oss_dev_alloc = 0;
+ }
+ if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT)
+ return 0;
snd_mixer_oss_proc_done(mixer);
return snd_mixer_oss_free1(mixer);
}
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index 472fce0ee0e..505b23ec405 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -2846,11 +2846,9 @@ static void snd_pcm_oss_proc_done(struct snd_pcm *pcm)
int stream;
for (stream = 0; stream < 2; ++stream) {
struct snd_pcm_str *pstr = &pcm->streams[stream];
- if (pstr->oss.proc_entry) {
- snd_info_unregister(pstr->oss.proc_entry);
- pstr->oss.proc_entry = NULL;
- snd_pcm_oss_proc_free_setup_list(pstr);
- }
+ snd_info_free_entry(pstr->oss.proc_entry);
+ pstr->oss.proc_entry = NULL;
+ snd_pcm_oss_proc_free_setup_list(pstr);
}
}
#else /* !CONFIG_SND_VERBOSE_PROCFS */
@@ -2931,25 +2929,23 @@ static int snd_pcm_oss_disconnect_minor(struct snd_pcm *pcm)
snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM,
pcm->card, 1);
}
- }
- return 0;
-}
-
-static int snd_pcm_oss_unregister_minor(struct snd_pcm *pcm)
-{
- snd_pcm_oss_disconnect_minor(pcm);
- if (pcm->oss.reg) {
if (dsp_map[pcm->card->number] == (int)pcm->device) {
#ifdef SNDRV_OSS_INFO_DEV_AUDIO
snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_AUDIO, pcm->card->number);
#endif
}
pcm->oss.reg = 0;
- snd_pcm_oss_proc_done(pcm);
}
return 0;
}
+static int snd_pcm_oss_unregister_minor(struct snd_pcm *pcm)
+{
+ snd_pcm_oss_disconnect_minor(pcm);
+ snd_pcm_oss_proc_done(pcm);
+ return 0;
+}
+
static struct snd_pcm_notify snd_pcm_oss_notify =
{
.n_register = snd_pcm_oss_register_minor,
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 7581edd7b9f..bf8f412988b 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -42,7 +42,6 @@ static int snd_pcm_free(struct snd_pcm *pcm);
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 int snd_pcm_dev_unregister(struct snd_device *device);
static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device)
{
@@ -494,19 +493,13 @@ static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr)
static int snd_pcm_stream_proc_done(struct snd_pcm_str *pstr)
{
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
- if (pstr->proc_xrun_debug_entry) {
- snd_info_unregister(pstr->proc_xrun_debug_entry);
- pstr->proc_xrun_debug_entry = NULL;
- }
+ snd_info_free_entry(pstr->proc_xrun_debug_entry);
+ pstr->proc_xrun_debug_entry = NULL;
#endif
- if (pstr->proc_info_entry) {
- snd_info_unregister(pstr->proc_info_entry);
- pstr->proc_info_entry = NULL;
- }
- if (pstr->proc_root) {
- snd_info_unregister(pstr->proc_root);
- pstr->proc_root = NULL;
- }
+ snd_info_free_entry(pstr->proc_info_entry);
+ pstr->proc_info_entry = NULL;
+ snd_info_free_entry(pstr->proc_root);
+ pstr->proc_root = NULL;
return 0;
}
@@ -570,29 +563,19 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream)
return 0;
}
-
+
static int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream)
{
- if (substream->proc_info_entry) {
- snd_info_unregister(substream->proc_info_entry);
- substream->proc_info_entry = NULL;
- }
- if (substream->proc_hw_params_entry) {
- snd_info_unregister(substream->proc_hw_params_entry);
- substream->proc_hw_params_entry = NULL;
- }
- if (substream->proc_sw_params_entry) {
- snd_info_unregister(substream->proc_sw_params_entry);
- substream->proc_sw_params_entry = NULL;
- }
- if (substream->proc_status_entry) {
- snd_info_unregister(substream->proc_status_entry);
- substream->proc_status_entry = NULL;
- }
- if (substream->proc_root) {
- snd_info_unregister(substream->proc_root);
- substream->proc_root = NULL;
- }
+ snd_info_free_entry(substream->proc_info_entry);
+ substream->proc_info_entry = NULL;
+ snd_info_free_entry(substream->proc_hw_params_entry);
+ substream->proc_hw_params_entry = NULL;
+ snd_info_free_entry(substream->proc_sw_params_entry);
+ substream->proc_sw_params_entry = NULL;
+ snd_info_free_entry(substream->proc_status_entry);
+ substream->proc_status_entry = NULL;
+ snd_info_free_entry(substream->proc_root);
+ substream->proc_root = NULL;
return 0;
}
#else /* !CONFIG_SND_VERBOSE_PROCFS */
@@ -696,7 +679,6 @@ int snd_pcm_new(struct snd_card *card, char *id, int device,
.dev_free = snd_pcm_dev_free,
.dev_register = snd_pcm_dev_register,
.dev_disconnect = snd_pcm_dev_disconnect,
- .dev_unregister = snd_pcm_dev_unregister
};
snd_assert(rpcm != NULL, return -EINVAL);
@@ -740,6 +722,7 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr)
substream = pstr->substream;
while (substream) {
substream_next = substream->next;
+ snd_pcm_timer_done(substream);
snd_pcm_substream_proc_done(substream);
kfree(substream);
substream = substream_next;
@@ -756,7 +739,12 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr)
static int snd_pcm_free(struct snd_pcm *pcm)
{
+ struct snd_pcm_notify *notify;
+
snd_assert(pcm != NULL, return -ENXIO);
+ list_for_each_entry(notify, &snd_pcm_notify_list, list) {
+ notify->n_unregister(pcm);
+ }
if (pcm->private_free)
pcm->private_free(pcm);
snd_pcm_lib_preallocate_free_for_all(pcm);
@@ -804,7 +792,8 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
kctl = snd_ctl_file(list);
if (kctl->pid == current->pid) {
prefer_subdevice = kctl->prefer_pcm_subdevice;
- break;
+ if (prefer_subdevice != -1)
+ break;
}
}
up_read(&card->controls_rwsem);
@@ -918,6 +907,28 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
substream->pstr->substream_opened--;
}
+static ssize_t show_pcm_class(struct class_device *class_device, char *buf)
+{
+ struct snd_pcm *pcm;
+ const char *str;
+ static const char *strs[SNDRV_PCM_CLASS_LAST + 1] = {
+ [SNDRV_PCM_CLASS_GENERIC] = "generic",
+ [SNDRV_PCM_CLASS_MULTI] = "multi",
+ [SNDRV_PCM_CLASS_MODEM] = "modem",
+ [SNDRV_PCM_CLASS_DIGITIZER] = "digitizer",
+ };
+
+ if (! (pcm = class_get_devdata(class_device)) ||
+ pcm->dev_class > SNDRV_PCM_CLASS_LAST)
+ str = "none";
+ else
+ str = strs[pcm->dev_class];
+ return snprintf(buf, PAGE_SIZE, "%s\n", str);
+}
+
+static struct class_device_attribute pcm_attrs =
+ __ATTR(pcm_class, S_IRUGO, show_pcm_class, NULL);
+
static int snd_pcm_dev_register(struct snd_device *device)
{
int cidx, err;
@@ -956,6 +967,8 @@ static int snd_pcm_dev_register(struct snd_device *device)
mutex_unlock(&register_mutex);
return err;
}
+ snd_add_device_sysfs_file(devtype, pcm->card, pcm->device,
+ &pcm_attrs);
for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
snd_pcm_timer_init(substream);
}
@@ -971,35 +984,22 @@ static int snd_pcm_dev_register(struct snd_device *device)
static int snd_pcm_dev_disconnect(struct snd_device *device)
{
struct snd_pcm *pcm = device->device_data;
- struct list_head *list;
+ struct snd_pcm_notify *notify;
struct snd_pcm_substream *substream;
- int cidx;
+ int cidx, devtype;
mutex_lock(&register_mutex);
+ if (list_empty(&pcm->list))
+ goto unlock;
+
list_del_init(&pcm->list);
for (cidx = 0; cidx < 2; cidx++)
for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
if (substream->runtime)
substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED;
- list_for_each(list, &snd_pcm_notify_list) {
- struct snd_pcm_notify *notify;
- notify = list_entry(list, struct snd_pcm_notify, list);
+ list_for_each_entry(notify, &snd_pcm_notify_list, list) {
notify->n_disconnect(pcm);
}
- mutex_unlock(&register_mutex);
- return 0;
-}
-
-static int snd_pcm_dev_unregister(struct snd_device *device)
-{
- int cidx, devtype;
- struct snd_pcm_substream *substream;
- struct list_head *list;
- struct snd_pcm *pcm = device->device_data;
-
- snd_assert(pcm != NULL, return -ENXIO);
- mutex_lock(&register_mutex);
- list_del(&pcm->list);
for (cidx = 0; cidx < 2; cidx++) {
devtype = -1;
switch (cidx) {
@@ -1011,23 +1011,20 @@ static int snd_pcm_dev_unregister(struct snd_device *device)
break;
}
snd_unregister_device(devtype, pcm->card, pcm->device);
- for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
- snd_pcm_timer_done(substream);
- }
- list_for_each(list, &snd_pcm_notify_list) {
- struct snd_pcm_notify *notify;
- notify = list_entry(list, struct snd_pcm_notify, list);
- notify->n_unregister(pcm);
}
+ unlock:
mutex_unlock(&register_mutex);
- return snd_pcm_free(pcm);
+ return 0;
}
int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
{
struct list_head *p;
- snd_assert(notify != NULL && notify->n_register != NULL && notify->n_unregister != NULL, return -EINVAL);
+ snd_assert(notify != NULL &&
+ notify->n_register != NULL &&
+ notify->n_unregister != NULL &&
+ notify->n_disconnect, return -EINVAL);
mutex_lock(&register_mutex);
if (nfree) {
list_del(&notify->list);
@@ -1090,8 +1087,7 @@ static void snd_pcm_proc_init(void)
static void snd_pcm_proc_done(void)
{
- if (snd_pcm_proc_entry)
- snd_info_unregister(snd_pcm_proc_entry);
+ snd_info_free_entry(snd_pcm_proc_entry);
}
#else /* !CONFIG_PROC_FS */
diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c
index 2b8aab6fd6c..2b539799d23 100644
--- a/sound/core/pcm_compat.c
+++ b/sound/core/pcm_compat.c
@@ -478,7 +478,7 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
* mmap of PCM status/control records because of the size
* incompatibility.
*/
- substream->no_mmap_ctrl = 1;
+ pcm_file->no_compat_mmap = 1;
switch (cmd) {
case SNDRV_PCM_IOCTL_PVERSION:
diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c
index 067d2056db9..be030cb4d37 100644
--- a/sound/core/pcm_memory.c
+++ b/sound/core/pcm_memory.c
@@ -101,7 +101,7 @@ int snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream)
{
snd_pcm_lib_preallocate_dma_free(substream);
#ifdef CONFIG_SND_VERBOSE_PROCFS
- snd_info_unregister(substream->proc_prealloc_entry);
+ snd_info_free_entry(substream->proc_prealloc_entry);
substream->proc_prealloc_entry = NULL;
#endif
return 0;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 439f047929e..0224c70414f 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -1992,35 +1992,9 @@ int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream)
return 0;
}
-static void snd_pcm_add_file(struct snd_pcm_str *str,
- struct snd_pcm_file *pcm_file)
-{
- pcm_file->next = str->files;
- str->files = pcm_file;
-}
-
-static void snd_pcm_remove_file(struct snd_pcm_str *str,
- struct snd_pcm_file *pcm_file)
-{
- struct snd_pcm_file * pcm_file1;
- if (str->files == pcm_file) {
- str->files = pcm_file->next;
- } else {
- pcm_file1 = str->files;
- while (pcm_file1 && pcm_file1->next != pcm_file)
- pcm_file1 = pcm_file1->next;
- if (pcm_file1 != NULL)
- pcm_file1->next = pcm_file->next;
- }
-}
-
static void pcm_release_private(struct snd_pcm_substream *substream)
{
- struct snd_pcm_file *pcm_file = substream->file;
-
snd_pcm_unlink(substream);
- snd_pcm_remove_file(substream->pstr, pcm_file);
- kfree(pcm_file);
}
void snd_pcm_release_substream(struct snd_pcm_substream *substream)
@@ -2060,7 +2034,6 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
return 0;
}
- substream->no_mmap_ctrl = 0;
err = snd_pcm_hw_constraints_init(substream);
if (err < 0) {
snd_printd("snd_pcm_hw_constraints_init failed\n");
@@ -2105,19 +2078,16 @@ static int snd_pcm_open_file(struct file *file,
if (err < 0)
return err;
- if (substream->ref_count > 1)
- pcm_file = substream->file;
- else {
- pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL);
- if (pcm_file == NULL) {
- snd_pcm_release_substream(substream);
- return -ENOMEM;
- }
+ pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL);
+ if (pcm_file == NULL) {
+ snd_pcm_release_substream(substream);
+ return -ENOMEM;
+ }
+ pcm_file->substream = substream;
+ if (substream->ref_count == 1) {
str = substream->pstr;
substream->file = pcm_file;
substream->pcm_release = pcm_release_private;
- pcm_file->substream = substream;
- snd_pcm_add_file(str, pcm_file);
}
file->private_data = pcm_file;
*rpcm_file = pcm_file;
@@ -2209,6 +2179,7 @@ static int snd_pcm_release(struct inode *inode, struct file *file)
fasync_helper(-1, file, 0, &substream->runtime->fasync);
mutex_lock(&pcm->open_mutex);
snd_pcm_release_substream(substream);
+ kfree(pcm_file);
mutex_unlock(&pcm->open_mutex);
wake_up(&pcm->open_wait);
module_put(pcm->card->module);
@@ -3270,11 +3241,11 @@ static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area)
offset = area->vm_pgoff << PAGE_SHIFT;
switch (offset) {
case SNDRV_PCM_MMAP_OFFSET_STATUS:
- if (substream->no_mmap_ctrl)
+ if (pcm_file->no_compat_mmap)
return -ENXIO;
return snd_pcm_mmap_status(substream, file, area);
case SNDRV_PCM_MMAP_OFFSET_CONTROL:
- if (substream->no_mmap_ctrl)
+ if (pcm_file->no_compat_mmap)
return -ENXIO;
return snd_pcm_mmap_control(substream, file, area);
default:
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index 8c15c66eb4a..269c467ca9b 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -55,7 +55,6 @@ static int snd_rawmidi_free(struct snd_rawmidi *rawmidi);
static int snd_rawmidi_dev_free(struct snd_device *device);
static int snd_rawmidi_dev_register(struct snd_device *device);
static int snd_rawmidi_dev_disconnect(struct snd_device *device);
-static int snd_rawmidi_dev_unregister(struct snd_device *device);
static LIST_HEAD(snd_rawmidi_devices);
static DEFINE_MUTEX(register_mutex);
@@ -431,7 +430,8 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
kctl = snd_ctl_file(list);
if (kctl->pid == current->pid) {
subdevice = kctl->prefer_rawmidi_subdevice;
- break;
+ if (subdevice != -1)
+ break;
}
}
up_read(&card->controls_rwsem);
@@ -1426,7 +1426,6 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device,
.dev_free = snd_rawmidi_dev_free,
.dev_register = snd_rawmidi_dev_register,
.dev_disconnect = snd_rawmidi_dev_disconnect,
- .dev_unregister = snd_rawmidi_dev_unregister
};
snd_assert(rrawmidi != NULL, return -EINVAL);
@@ -1479,6 +1478,14 @@ static void snd_rawmidi_free_substreams(struct snd_rawmidi_str *stream)
static int snd_rawmidi_free(struct snd_rawmidi *rmidi)
{
snd_assert(rmidi != NULL, return -ENXIO);
+
+ snd_info_free_entry(rmidi->proc_entry);
+ rmidi->proc_entry = NULL;
+ mutex_lock(&register_mutex);
+ if (rmidi->ops && rmidi->ops->dev_unregister)
+ rmidi->ops->dev_unregister(rmidi);
+ mutex_unlock(&register_mutex);
+
snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]);
snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]);
if (rmidi->private_free)
@@ -1587,21 +1594,6 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device)
mutex_lock(&register_mutex);
list_del_init(&rmidi->list);
- mutex_unlock(&register_mutex);
- return 0;
-}
-
-static int snd_rawmidi_dev_unregister(struct snd_device *device)
-{
- struct snd_rawmidi *rmidi = device->device_data;
-
- snd_assert(rmidi != NULL, return -ENXIO);
- mutex_lock(&register_mutex);
- list_del(&rmidi->list);
- if (rmidi->proc_entry) {
- snd_info_unregister(rmidi->proc_entry);
- rmidi->proc_entry = NULL;
- }
#ifdef CONFIG_SND_OSSEMUL
if (rmidi->ossreg) {
if ((int)rmidi->device == midi_map[rmidi->card->number]) {
@@ -1615,17 +1607,9 @@ static int snd_rawmidi_dev_unregister(struct snd_device *device)
rmidi->ossreg = 0;
}
#endif /* CONFIG_SND_OSSEMUL */
- if (rmidi->ops && rmidi->ops->dev_unregister)
- rmidi->ops->dev_unregister(rmidi);
snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device);
mutex_unlock(&register_mutex);
-#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
- if (rmidi->seq_dev) {
- snd_device_free(rmidi->card, rmidi->seq_dev);
- rmidi->seq_dev = NULL;
- }
-#endif
- return snd_rawmidi_free(rmidi);
+ return 0;
}
/**
diff --git a/sound/core/rtctimer.c b/sound/core/rtctimer.c
index 84704ccb182..412dd62b654 100644
--- a/sound/core/rtctimer.c
+++ b/sound/core/rtctimer.c
@@ -156,7 +156,7 @@ static int __init rtctimer_init(void)
static void __exit rtctimer_exit(void)
{
if (rtctimer) {
- snd_timer_global_unregister(rtctimer);
+ snd_timer_global_free(rtctimer);
rtctimer = NULL;
}
}
diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c
index e7234135641..92858cf8b6e 100644
--- a/sound/core/seq/oss/seq_oss.c
+++ b/sound/core/seq/oss/seq_oss.c
@@ -303,8 +303,7 @@ register_proc(void)
static void
unregister_proc(void)
{
- if (info_entry)
- snd_info_unregister(info_entry);
+ snd_info_free_entry(info_entry);
info_entry = NULL;
}
#endif /* CONFIG_PROC_FS */
diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c
index 102ff548ce6..b79d011813c 100644
--- a/sound/core/seq/seq_device.c
+++ b/sound/core/seq/seq_device.c
@@ -90,7 +90,6 @@ static int snd_seq_device_free(struct snd_seq_device *dev);
static int snd_seq_device_dev_free(struct snd_device *device);
static int snd_seq_device_dev_register(struct snd_device *device);
static int snd_seq_device_dev_disconnect(struct snd_device *device);
-static int snd_seq_device_dev_unregister(struct snd_device *device);
static int init_device(struct snd_seq_device *dev, struct ops_list *ops);
static int free_device(struct snd_seq_device *dev, struct ops_list *ops);
@@ -189,7 +188,6 @@ int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize,
.dev_free = snd_seq_device_dev_free,
.dev_register = snd_seq_device_dev_register,
.dev_disconnect = snd_seq_device_dev_disconnect,
- .dev_unregister = snd_seq_device_dev_unregister
};
if (result)
@@ -309,15 +307,6 @@ static int snd_seq_device_dev_disconnect(struct snd_device *device)
}
/*
- * unregister the existing device
- */
-static int snd_seq_device_dev_unregister(struct snd_device *device)
-{
- struct snd_seq_device *dev = device->device_data;
- return snd_seq_device_free(dev);
-}
-
-/*
* register device driver
* id = driver id
* entry = driver operators - duplicated to each instance
@@ -573,7 +562,7 @@ static void __exit alsa_seq_device_exit(void)
{
remove_drivers();
#ifdef CONFIG_PROC_FS
- snd_info_unregister(info_entry);
+ snd_info_free_entry(info_entry);
#endif
if (num_ops)
snd_printk(KERN_ERR "drivers not released (%d)\n", num_ops);
diff --git a/sound/core/seq/seq_info.c b/sound/core/seq/seq_info.c
index 142e9e6882c..8a7fe5cca1c 100644
--- a/sound/core/seq/seq_info.c
+++ b/sound/core/seq/seq_info.c
@@ -64,9 +64,9 @@ int __init snd_seq_info_init(void)
int __exit snd_seq_info_done(void)
{
- snd_info_unregister(queues_entry);
- snd_info_unregister(clients_entry);
- snd_info_unregister(timer_entry);
+ snd_info_free_entry(queues_entry);
+ snd_info_free_entry(clients_entry);
+ snd_info_free_entry(timer_entry);
return 0;
}
#endif
diff --git a/sound/core/sound.c b/sound/core/sound.c
index 7edd1fc58b1..efa476c5210 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -268,7 +268,11 @@ int snd_register_device(int type, struct snd_card *card, int dev,
snd_minors[minor] = preg;
if (card)
device = card->dev;
- class_device_create(sound_class, NULL, MKDEV(major, minor), device, "%s", name);
+ preg->class_dev = class_device_create(sound_class, NULL,
+ MKDEV(major, minor),
+ device, "%s", name);
+ if (preg->class_dev)
+ class_set_devdata(preg->class_dev, private_data);
mutex_unlock(&sound_mutex);
return 0;
@@ -276,6 +280,24 @@ int snd_register_device(int type, struct snd_card *card, int dev,
EXPORT_SYMBOL(snd_register_device);
+/* find the matching minor record
+ * return the index of snd_minor, or -1 if not found
+ */
+static int find_snd_minor(int type, struct snd_card *card, int dev)
+{
+ int cardnum, minor;
+ struct snd_minor *mptr;
+
+ cardnum = card ? card->number : -1;
+ for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor)
+ if ((mptr = snd_minors[minor]) != NULL &&
+ mptr->type == type &&
+ mptr->card == cardnum &&
+ mptr->device == dev)
+ return minor;
+ return -1;
+}
+
/**
* snd_unregister_device - unregister the device on the given card
* @type: the device type, SNDRV_DEVICE_TYPE_XXX
@@ -289,32 +311,42 @@ EXPORT_SYMBOL(snd_register_device);
*/
int snd_unregister_device(int type, struct snd_card *card, int dev)
{
- int cardnum, minor;
- struct snd_minor *mptr;
+ int minor;
- cardnum = card ? card->number : -1;
mutex_lock(&sound_mutex);
- for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor)
- if ((mptr = snd_minors[minor]) != NULL &&
- mptr->type == type &&
- mptr->card == cardnum &&
- mptr->device == dev)
- break;
- if (minor == ARRAY_SIZE(snd_minors)) {
+ minor = find_snd_minor(type, card, dev);
+ if (minor < 0) {
mutex_unlock(&sound_mutex);
return -EINVAL;
}
class_device_destroy(sound_class, MKDEV(major, minor));
+ kfree(snd_minors[minor]);
snd_minors[minor] = NULL;
mutex_unlock(&sound_mutex);
- kfree(mptr);
return 0;
}
EXPORT_SYMBOL(snd_unregister_device);
+int snd_add_device_sysfs_file(int type, struct snd_card *card, int dev,
+ const struct class_device_attribute *attr)
+{
+ int minor, ret = -EINVAL;
+ struct class_device *cdev;
+
+ mutex_lock(&sound_mutex);
+ minor = find_snd_minor(type, card, dev);
+ if (minor >= 0 && (cdev = snd_minors[minor]->class_dev) != NULL)
+ ret = class_device_create_file(cdev, attr);
+ mutex_unlock(&sound_mutex);
+ return ret;
+
+}
+
+EXPORT_SYMBOL(snd_add_device_sysfs_file);
+
#ifdef CONFIG_PROC_FS
/*
* INFO PART
@@ -387,8 +419,7 @@ int __init snd_minor_info_init(void)
int __exit snd_minor_info_done(void)
{
- if (snd_minor_info_entry)
- snd_info_unregister(snd_minor_info_entry);
+ snd_info_free_entry(snd_minor_info_entry);
return 0;
}
#endif /* CONFIG_PROC_FS */
diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c
index 74f0fe5a1ba..b2fc40aa520 100644
--- a/sound/core/sound_oss.c
+++ b/sound/core/sound_oss.c
@@ -270,8 +270,7 @@ int __init snd_minor_info_oss_init(void)
int __exit snd_minor_info_oss_done(void)
{
- if (snd_minor_info_oss_entry)
- snd_info_unregister(snd_minor_info_oss_entry);
+ snd_info_free_entry(snd_minor_info_oss_entry);
return 0;
}
#endif /* CONFIG_PROC_FS */
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 0a984e881c1..10a79aed33f 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -88,7 +88,7 @@ static DEFINE_MUTEX(register_mutex);
static int snd_timer_free(struct snd_timer *timer);
static int snd_timer_dev_free(struct snd_device *device);
static int snd_timer_dev_register(struct snd_device *device);
-static int snd_timer_dev_unregister(struct snd_device *device);
+static int snd_timer_dev_disconnect(struct snd_device *device);
static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_left);
@@ -718,7 +718,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
}
}
if (timer->flags & SNDRV_TIMER_FLG_RESCHED)
- snd_timer_reschedule(timer, ticks_left);
+ snd_timer_reschedule(timer, timer->sticks);
if (timer->running) {
if (timer->hw.flags & SNDRV_TIMER_HW_STOP) {
timer->hw.stop(timer);
@@ -773,7 +773,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
static struct snd_device_ops ops = {
.dev_free = snd_timer_dev_free,
.dev_register = snd_timer_dev_register,
- .dev_unregister = snd_timer_dev_unregister
+ .dev_disconnect = snd_timer_dev_disconnect,
};
snd_assert(tid != NULL, return -EINVAL);
@@ -813,6 +813,21 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
static int snd_timer_free(struct snd_timer *timer)
{
snd_assert(timer != NULL, return -ENXIO);
+
+ mutex_lock(&register_mutex);
+ if (! list_empty(&timer->open_list_head)) {
+ struct list_head *p, *n;
+ struct snd_timer_instance *ti;
+ snd_printk(KERN_WARNING "timer %p is busy?\n", timer);
+ list_for_each_safe(p, n, &timer->open_list_head) {
+ list_del_init(p);
+ ti = list_entry(p, struct snd_timer_instance, open_list);
+ ti->timer = NULL;
+ }
+ }
+ list_del(&timer->device_list);
+ mutex_unlock(&register_mutex);
+
if (timer->private_free)
timer->private_free(timer);
kfree(timer);
@@ -867,30 +882,13 @@ static int snd_timer_dev_register(struct snd_device *dev)
return 0;
}
-static int snd_timer_unregister(struct snd_timer *timer)
+static int snd_timer_dev_disconnect(struct snd_device *device)
{
- struct list_head *p, *n;
- struct snd_timer_instance *ti;
-
- snd_assert(timer != NULL, return -ENXIO);
+ struct snd_timer *timer = device->device_data;
mutex_lock(&register_mutex);
- if (! list_empty(&timer->open_list_head)) {
- snd_printk(KERN_WARNING "timer 0x%lx is busy?\n", (long)timer);
- list_for_each_safe(p, n, &timer->open_list_head) {
- list_del_init(p);
- ti = list_entry(p, struct snd_timer_instance, open_list);
- ti->timer = NULL;
- }
- }
- list_del(&timer->device_list);
+ list_del_init(&timer->device_list);
mutex_unlock(&register_mutex);
- return snd_timer_free(timer);
-}
-
-static int snd_timer_dev_unregister(struct snd_device *device)
-{
- struct snd_timer *timer = device->device_data;
- return snd_timer_unregister(timer);
+ return 0;
}
void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstamp)
@@ -955,18 +953,12 @@ int snd_timer_global_register(struct snd_timer *timer)
return snd_timer_dev_register(&dev);
}
-int snd_timer_global_unregister(struct snd_timer *timer)
-{
- return snd_timer_unregister(timer);
-}
-
/*
* System timer
*/
struct snd_timer_system_private {
struct timer_list tlist;
- struct timer * timer;
unsigned long last_expires;
unsigned long last_jiffies;
unsigned long correction;
@@ -978,7 +970,7 @@ static void snd_timer_s_function(unsigned long data)
struct snd_timer_system_private *priv = timer->private_data;
unsigned long jiff = jiffies;
if (time_after(jiff, priv->last_expires))
- priv->correction = (long)jiff - (long)priv->last_expires;
+ priv->correction += (long)jiff - (long)priv->last_expires;
snd_timer_interrupt(timer, (long)jiff - (long)priv->last_jiffies);
}
@@ -994,7 +986,7 @@ static int snd_timer_s_start(struct snd_timer * timer)
njiff++;
} else {
njiff += timer->sticks - priv->correction;
- priv->correction -= timer->sticks;
+ priv->correction = 0;
}
priv->last_expires = priv->tlist.expires = njiff;
add_timer(&priv->tlist);
@@ -1013,6 +1005,7 @@ static int snd_timer_s_stop(struct snd_timer * timer)
timer->sticks = priv->last_expires - jiff;
else
timer->sticks = 1;
+ priv->correction = 0;
return 0;
}
@@ -1126,7 +1119,7 @@ static void __init snd_timer_proc_init(void)
static void __exit snd_timer_proc_done(void)
{
- snd_info_unregister(snd_timer_proc_entry);
+ snd_info_free_entry(snd_timer_proc_entry);
}
#else /* !CONFIG_PROC_FS */
#define snd_timer_proc_init()
@@ -1982,7 +1975,7 @@ static void __exit alsa_timer_exit(void)
/* unregister the system timer */
list_for_each_safe(p, n, &snd_timer_list) {
struct snd_timer *timer = list_entry(p, struct snd_timer, device_list);
- snd_timer_unregister(timer);
+ snd_timer_free(timer);
}
snd_timer_proc_done();
#ifdef SNDRV_OSS_INFO_DEV_TIMERS
@@ -2005,5 +1998,4 @@ EXPORT_SYMBOL(snd_timer_notify);
EXPORT_SYMBOL(snd_timer_global_new);
EXPORT_SYMBOL(snd_timer_global_free);
EXPORT_SYMBOL(snd_timer_global_register);
-EXPORT_SYMBOL(snd_timer_global_unregister);
EXPORT_SYMBOL(snd_timer_interrupt);